Tres Seaver
2015-11-12 b4c96d2892d8271b300b1920e3ce5d2c0eae588b
Merge branch 'master' into feature/alchemy-scaffold-update

Conflicts:
docs/tutorials/wiki2/basiclayout.rst
14 files deleted
12 files added
48 files modified
3 files renamed
5916 ■■■■ changed files
CHANGES.txt 21 ●●●●● patch | view | raw | blame | history
CONTRIBUTORS.txt 4 ●●●● patch | view | raw | blame | history
TODO.txt 8 ●●●● patch | view | raw | blame | history
contributing.md 32 ●●●● patch | view | raw | blame | history
docs/index.rst 153 ●●●● patch | view | raw | blame | history
docs/narr/advconfig.rst 133 ●●●● patch | view | raw | blame | history
docs/narr/commandline.rst 80 ●●●●● patch | view | raw | blame | history
docs/narr/extconfig.rst 261 ●●●● patch | view | raw | blame | history
docs/narr/extending.rst 194 ●●●● patch | view | raw | blame | history
docs/narr/hellotraversal.rst 67 ●●●● patch | view | raw | blame | history
docs/narr/hooks.rst 638 ●●●● patch | view | raw | blame | history
docs/narr/hybrid.rst 539 ●●●●● patch | view | raw | blame | history
docs/narr/introspector.rst 123 ●●●● patch | view | raw | blame | history
docs/narr/muchadoabouttraversal.rst 325 ●●●● patch | view | raw | blame | history
docs/narr/renderers.rst 4 ●●●● patch | view | raw | blame | history
docs/narr/resources.rst 386 ●●●● patch | view | raw | blame | history
docs/narr/scaffolding.rst 100 ●●●● patch | view | raw | blame | history
docs/narr/security.rst 434 ●●●● patch | view | raw | blame | history
docs/narr/subrequest.rst 154 ●●●● patch | view | raw | blame | history
docs/narr/tb_introspector.png patch | view | raw | blame | history
docs/narr/testing.rst 193 ●●●● patch | view | raw | blame | history
docs/narr/traversal.rst 423 ●●●● patch | view | raw | blame | history
docs/quick_tour.rst 4 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/development.ini 4 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/production.ini 2 ●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/setup.py 11 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo.sqlite patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/__init__.py 11 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models.py 29 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py 7 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/meta.py 46 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py 19 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/scripts/initializedb.py 30 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/favicon.ico patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/footerbg.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/headerbg.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/ie6.css 8 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/middlebg.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pylons.css 372 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-16x16.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-small.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid.png patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/theme.css 154 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/theme.min.css 1 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/static/transparent.gif patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 66 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.jinja2 8 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.pt 76 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/tests.py 68 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/views.py 18 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/views/__init__.py patch | view | raw | blame | history
docs/tutorials/wiki2/basiclayout.rst 65 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/development.ini 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/production.ini 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py 12 ●●●● patch | view | raw | blame | history
pyramid/config/routes.py 6 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/__init__.py 12 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models.py 27 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/__init__.py 7 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/meta.py 46 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/mymodel.py 17 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py 21 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/templates/mytemplate.jinja2_tmpl 8 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl 15 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/tests.py_tmpl 80 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/views.py_tmpl 15 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/views/__init__.py patch | view | raw | blame | history
pyramid/scaffolds/alchemy/setup.py_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/scaffolds/copydir.py 15 ●●●●● patch | view | raw | blame | history
pyramid/scripts/pserve.py 2 ●●● patch | view | raw | blame | history
pyramid/scripts/pshell.py 116 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_authentication.py 1 ●●●● patch | view | raw | blame | history
pyramid/tests/test_router.py 2 ●●● patch | view | raw | blame | history
pyramid/tests/test_scripts/dummy.py 20 ●●●● patch | view | raw | blame | history
pyramid/tests/test_scripts/test_pshell.py 208 ●●●● patch | view | raw | blame | history
pyramid/util.py 2 ●●● patch | view | raw | blame | history
setup.py 5 ●●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -1,6 +1,19 @@
1.6 (2015-04-14)
================
Backward Incompatibilities
--------------------------
- IPython and BPython support have been removed from pshell in the core.
  To continue using them on Pyramid 1.6+ you must install the binding
  packages explicitly::
    $ pip install pyramid_ipython
    or
    $ pip install pyramid_bpython
Features
--------
@@ -135,7 +148,8 @@
  https://github.com/Pylons/pyramid/pull/1610
- Additional shells for ``pshell`` can now be registered as entrypoints. See
  https://github.com/Pylons/pyramid/pull/1891
  https://github.com/Pylons/pyramid/pull/1891 and
  https://github.com/Pylons/pyramid/pull/2012
- The variables injected into ``pshell`` are now displayed with their
  docstrings instead of the default ``str(obj)`` when possible.
@@ -213,6 +227,11 @@
  WebOb 1.5.
  See https://github.com/Pylons/pyramid/pull/1865
- ``pshell`` will now preserve the capitalization of variables in the
  ``[pshell]`` section of the INI file. This makes exposing classes to the
  shell a little more straightfoward.
  See https://github.com/Pylons/pyramid/pull/1883
Deprecations
------------
CONTRIBUTORS.txt
@@ -247,10 +247,10 @@
- Donald Stufft, 2015/03/15
- Randy Topliffe, 2015/04/14
- Karen Dalton, 2015/06/01
- Igor Stroh, 2015/06/10
- Jesse Dhillon, 2015/10/07
- Amos Latteier, 2015/10/22
TODO.txt
@@ -47,11 +47,9 @@
  the templates chapter and elsewhere.  Scan the documentation for reference
  to a renderer as *only* view configuration (it's a larger concept now).
- Add better docs about what-to-do-when-behind-a-proxy: paste.urlmap ("/foo =
- Add better docs about what-to-do-when-behind-a-proxy: rutter ("/foo =
  app1" and "domain app1.localhost = app1"), ProxyPreserveHost and the nginx
  equivalent, preserving HTTPS URLs.
- Alias the stupid long default session factory name.
  proxy_params, preserving HTTPS URLs.
- Debug option to print view matching decision (e.g. debug_viewlookup or so).
@@ -163,3 +161,5 @@
- _fix_registry should dictify the registry being fixed.
- Apply a prefix to the userid principal to avoid poisoning the principal
  namespace. See https://github.com/Pylons/pyramid/issues/2060
contributing.md
@@ -3,7 +3,9 @@
All projects under the Pylons Projects, including this one, follow the
guidelines established at [How to
Contribute](http://www.pylonsproject.org/community/how-to-contribute).
Contribute](http://www.pylonsproject.org/community/how-to-contribute) and
[Coding Style and
Standards](http://docs.pylonsproject.org/en/latest/community/codestyle.html).
You can contribute to this project in several ways.
@@ -13,10 +15,27 @@
  Flow](https://guides.github.com/introduction/flow/index.html) describes the
  workflow process and why it's a good practice. When submitting a pull
  request, sign
  [CONTRIBUTORS.txt](https://github.com/Pylons/pyramid/blob/master/CONTRIBUTORS.
txt)
  [CONTRIBUTORS.txt](https://github.com/Pylons/pyramid/blob/master/CONTRIBUTORS.txt)
  if you have not yet done so.
* Join the IRC channel #pyramid on irc.freenode.net.
Git Branches
------------
Git branches and their purpose and status at the time of this writing are
listed below.
* [master](https://github.com/Pylons/pyramid/) - The branch on which further
development takes place. The default branch on GitHub.
* [1.6-branch](https://github.com/Pylons/pyramid/tree/1.6-branch) - The branch
to which further development on master should be backported. This is also a
development branch.
* [1.5-branch](https://github.com/Pylons/pyramid/tree/1.5-branch) - The branch
classified as "stable" or "latest". Actively maintained.
* [1.4-branch](https://github.com/Pylons/pyramid/tree/1.4-branch) - The oldest
actively maintained and stable branch.
Older branches are not actively maintained. In general, two stable branches and
one or two development branches are actively maintained.
Prerequisites
-------------
@@ -38,7 +57,7 @@
1.  Fork the repo on GitHub by clicking the [Fork] button.
2.  Clone your fork into a workspace on your local machine.
         git@github.com:<username>/pyramid.git
         git clone git@github.com:<username>/pyramid.git
3.  Add a git remote "upstream" for the cloned fork.
@@ -65,8 +84,9 @@
     load the built documentation in the `/_build/html/` directory in a web
     browser.
6.  From this point forward, follow the typical git workflow.  Start by pulling
    from the upstream to get the most current changes.
6.  From this point forward, follow the typical [git
    workflow](https://help.github.com/articles/what-is-a-good-git-workflow/).
    Start by pulling from the upstream to get the most current changes.
         git pull upstream master
docs/index.rst
@@ -4,10 +4,9 @@
The Pyramid Web Framework
=========================
:app:`Pyramid` is a small, fast, down-to-earth Python web framework.  It
is developed as part of the `Pylons Project
<http://docs.pylonsproject.org/>`_.  It is licensed under a `BSD-like license
<http://repoze.org/license.html>`_.
:app:`Pyramid` is a small, fast, down-to-earth Python web framework.  It is
developed as part of the `Pylons Project <http://docs.pylonsproject.org/>`_.
It is licensed under a `BSD-like license <http://repoze.org/license.html>`_.
Here is one of the simplest :app:`Pyramid` applications you can make:
@@ -15,30 +14,17 @@
After you install :app:`Pyramid` and run this application, when you visit
`<http://localhost:8080/hello/world>`_ in a browser, you will see the text
``Hello, world!``
``Hello, world!`` See :ref:`firstapp_chapter` for a full explanation of how
this application works.
See :ref:`firstapp_chapter` for a full explanation of how this application
works. Read the :ref:`html_narrative_documentation` to understand how
:app:`Pyramid` is designed to scale from simple applications like this to
very large web applications.  To just dive in headfirst, read the
:doc:`quick_tour`.
Front Matter
============
.. toctree::
   :maxdepth: 1
   copyright.rst
   conventions.rst
.. _html_getting_started:
Getting Started
===============
If you are new to Pyramid, we have a few resources that can help you get
up to speed right away.
If you are new to Pyramid, we have a few resources that can help you get up to
speed right away.
.. toctree::
   :hidden:
@@ -46,26 +32,69 @@
   quick_tour
   quick_tutorial/index
* :doc:`quick_tour` goes through the major features in Pyramid, covering
  a little about a lot.
* :doc:`quick_tour` gives an overview of the major features in Pyramid,
  covering a little about a lot.
* :doc:`quick_tutorial/index` does the same, but in a tutorial format:
  deeper treatment of each topic and with working code.
* :doc:`quick_tutorial/index` is similar to the Quick Tour, but in a tutorial
  format, with somewhat deeper treatment of each topic and with working code.
* To see a minimal Pyramid web application, check out
  :ref:`firstapp_chapter`.
* Like learning by example? Visit the official :ref:`html_tutorials` as well as
  the community-contributed :ref:`Pyramid tutorials
  <tutorials:pyramid-tutorials>`, which include a :ref:`Todo List Application
  in One File <tutorials:single-file-tutorial>`.
* For help getting Pyramid set up, try
  :ref:`installing_chapter`.
* For help getting Pyramid set up, try :ref:`installing_chapter`.
* Like learning by example? Visit the official
  :doc:`wiki tutorial <../tutorials/wiki2/index>` as well as the
  community-contributed
  :ref:`Pyramid tutorials <tutorials:pyramid-tutorials>`, which include
  a :ref:`single file tasks tutorial <tutorials:single-file-tutorial>`.
* Need help?  See :ref:`Support and Development <support-and-development>`.
* Need help?  See :ref:`Support and
  Development <support-and-development>`.
.. _html_tutorials:
Tutorials
=========
Official tutorials explaining how to use :app:`Pyramid` to build various types
of applications, and how to deploy :app:`Pyramid` applications to various
platforms.
.. toctree::
   :maxdepth: 1
   tutorials/wiki2/index.rst
   tutorials/wiki/index.rst
   tutorials/modwsgi/index.rst
.. _support-and-development:
Support and Development
=======================
The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
source of :app:`Pyramid` support and development information.
To report bugs, use the `issue tracker
<https://github.com/Pylons/pyramid/issues>`_.
If you've got questions that aren't answered by this documentation, contact the
`Pylons-discuss maillist <http://groups.google.com/group/pylons-discuss>`_ or
join the `#pyramid IRC channel <irc://irc.freenode.net/#pyramid>`_.
Browse and check out tagged and trunk versions of :app:`Pyramid` via the
`Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_. To check out
the trunk via ``git``, use either command:
.. code-block:: text
  # If you have SSH keys configured on GitHub:
  git clone git@github.com:Pylons/pyramid.git
  # Otherwise, HTTPS will work, using your GitHub login:
  git clone https://github.com/Pylons/pyramid.git
To find out how to become a contributor to :app:`Pyramid`, please see the
`contributor's section of the documentation
<http://docs.pylonsproject.org/en/latest/#contributing>`_.
.. _html_narrative_documentation:
@@ -73,8 +102,7 @@
Narrative Documentation
=======================
Narrative documentation in chapter form explaining how to use
:app:`Pyramid`.
Narrative documentation in chapter form explaining how to use :app:`Pyramid`.
.. toctree::
   :maxdepth: 2
@@ -119,26 +147,12 @@
   narr/threadlocals
   narr/zca
.. _html_tutorials:
Tutorials
=========
Tutorials explaining how to use :app:`Pyramid` to build various types of
applications, and how to deploy :app:`Pyramid` applications to various
platforms.
.. toctree::
   :maxdepth: 2
   tutorials/wiki2/index.rst
   tutorials/wiki/index.rst
   tutorials/modwsgi/index.rst
API Documentation
=================
Comprehensive reference material for every public API exposed by :app:`Pyramid`:
Comprehensive reference material for every public API exposed by
:app:`Pyramid`:
.. toctree::
   :maxdepth: 1
@@ -146,6 +160,7 @@
   api/index
   api/*
Change History
==============
@@ -162,6 +177,7 @@
   whatsnew-1.0
   changes
Design Documents
================
@@ -170,33 +186,24 @@
   designdefense
.. _support-and-development:
Support and Development
=======================
Copyright, Trademarks, and Attributions
=======================================
The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
source of :app:`Pyramid` support and development information.
.. toctree::
   :maxdepth: 1
To report bugs, use the `issue tracker
<https://github.com/Pylons/pyramid/issues>`_.
   copyright
If you've got questions that aren't answered by this documentation,
contact the `Pylons-discuss maillist
<http://groups.google.com/group/pylons-discuss>`_ or join the `#pyramid
IRC channel <irc://irc.freenode.net/#pyramid>`_.
Browse and check out tagged and trunk versions of :app:`Pyramid` via
the `Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_.
To check out the trunk via ``git``, use this command:
Typographical Conventions
=========================
.. code-block:: text
.. toctree::
   :maxdepth: 1
  git clone git@github.com:Pylons/pyramid.git
   conventions
To find out how to become a contributor to :app:`Pyramid`, please see the
`contributor's section of the documentation
<http://docs.pylonsproject.org/en/latest/#contributing>`_.
Index and Glossary
==================
docs/narr/advconfig.rst
@@ -6,12 +6,11 @@
Advanced Configuration
======================
To support application extensibility, the :app:`Pyramid`
:term:`Configurator`, by default, detects configuration conflicts and allows
you to include configuration imperatively from other packages or modules.  It
also, by default, performs configuration in two separate phases.  This allows
you to ignore relative configuration statement ordering in some
circumstances.
To support application extensibility, the :app:`Pyramid` :term:`Configurator`
by default detects configuration conflicts and allows you to include
configuration imperatively from other packages or modules.  It also by default
performs configuration in two separate phases.  This allows you to ignore
relative configuration statement ordering in some circumstances.
.. index::
   pair: configuration; conflict detection
@@ -70,11 +69,11 @@
       server = make_server('0.0.0.0', 8080, app)
       server.serve_forever()
The application now has two conflicting view configuration statements.  When
we try to start it again, it won't start.  Instead, we'll receive a traceback
that ends something like this:
The application now has two conflicting view configuration statements.  When we
try to start it again, it won't start.  Instead we'll receive a traceback that
ends something like this:
.. code-block:: guess
.. code-block:: text
   :linenos:
   Traceback (most recent call last):
@@ -94,19 +93,19 @@
This traceback is trying to tell us:
- We've got conflicting information for a set of view configuration
  statements (The ``For:`` line).
- We've got conflicting information for a set of view configuration statements
  (The ``For:`` line).
- There are two statements which conflict, shown beneath the ``For:`` line:
  ``config.add_view(hello_world. 'hello')`` on line 14 of ``app.py``, and
  ``config.add_view(goodbye_world, 'hello')`` on line 17 of ``app.py``.
These two configuration statements are in conflict because we've tried to
tell the system that the set of :term:`predicate` values for both view
These two configuration statements are in conflict because we've tried to tell
the system that the set of :term:`predicate` values for both view
configurations are exactly the same.  Both the ``hello_world`` and
``goodbye_world`` views are configured to respond under the same set of
circumstances.  This circumstance: the :term:`view name` (represented by the
``name=`` predicate) is ``hello``.
circumstances.  This circumstance, the :term:`view name` represented by the
``name=`` predicate, is ``hello``.
This presents an ambiguity that :app:`Pyramid` cannot resolve. Rather than
allowing the circumstance to go unreported, by default Pyramid raises a
@@ -138,8 +137,7 @@
modify your configuration code accordingly.
If you're getting a conflict while trying to extend an existing application,
and that application has a function which performs configuration like this
one:
and that application has a function which performs configuration like this one:
.. code-block:: python
   :linenos:
@@ -147,8 +145,8 @@
   def add_routes(config):
       config.add_route(...)
Don't call this function directly with ``config`` as an argument.  Instead,
use :meth:`pyramid.config.Configurator.include`:
Don't call this function directly with ``config`` as an argument.  Instead, use
:meth:`pyramid.config.Configurator.include`:
.. code-block:: python
   :linenos:
@@ -156,9 +154,9 @@
   config.include(add_routes)
Using :meth:`~pyramid.config.Configurator.include` instead of calling the
function directly provides a modicum of automated conflict resolution, with
the configuration statements you define in the calling code overriding those
of the included function.
function directly provides a modicum of automated conflict resolution, with the
configuration statements you define in the calling code overriding those of the
included function.
.. seealso::
@@ -169,10 +167,10 @@
+++++++++++++++++++++++++
You can manually commit a configuration by using the
:meth:`~pyramid.config.Configurator.commit` method between configuration
calls.  For example, we prevent conflicts from occurring in the application
we examined previously as the result of adding a ``commit``.  Here's the
application that generates conflicts:
:meth:`~pyramid.config.Configurator.commit` method between configuration calls.
For example, we prevent conflicts from occurring in the application we examined
previously as the result of adding a ``commit``.  Here's the application that
generates conflicts:
.. code-block:: python
   :linenos:
@@ -199,11 +197,12 @@
       server = make_server('0.0.0.0', 8080, app)
       server.serve_forever()
We can prevent the two ``add_view`` calls from conflicting by issuing a call
to :meth:`~pyramid.config.Configurator.commit` between them:
We can prevent the two ``add_view`` calls from conflicting by issuing a call to
:meth:`~pyramid.config.Configurator.commit` between them:
.. code-block:: python
   :linenos:
   :emphasize-lines: 16
   from wsgiref.simple_server import make_server
   from pyramid.config import Configurator
@@ -230,21 +229,20 @@
       server.serve_forever()
In the above example we've issued a call to
:meth:`~pyramid.config.Configurator.commit` between the two ``add_view``
calls.  :meth:`~pyramid.config.Configurator.commit` will execute any pending
:meth:`~pyramid.config.Configurator.commit` between the two ``add_view`` calls.
:meth:`~pyramid.config.Configurator.commit` will execute any pending
configuration statements.
Calling :meth:`~pyramid.config.Configurator.commit` is safe at any time.  It
executes all pending configuration actions and leaves the configuration
action list "clean".
executes all pending configuration actions and leaves the configuration action
list "clean".
Note that :meth:`~pyramid.config.Configurator.commit` has no effect when
you're using an *autocommitting* configurator (see
:ref:`autocommitting_configurator`).
Note that :meth:`~pyramid.config.Configurator.commit` has no effect when you're
using an *autocommitting* configurator (see :ref:`autocommitting_configurator`).
.. _autocommitting_configurator:
Using An Autocommitting Configurator
Using an Autocommitting Configurator
++++++++++++++++++++++++++++++++++++
You can also use a heavy hammer to circumvent conflict detection by using a
@@ -278,17 +276,17 @@
If your code uses the :meth:`~pyramid.config.Configurator.include` method to
include external configuration, some conflicts are automatically resolved.
Configuration statements that are made as the result of an "include" will be
overridden by configuration statements that happen within the caller of
the "include" method.
overridden by configuration statements that happen within the caller of the
"include" method.
Automatic conflict resolution supports this goal: if a user wants to reuse a
Automatic conflict resolution supports this goal.  If a user wants to reuse a
Pyramid application, and they want to customize the configuration of this
application without hacking its code "from outside", they can "include" a
configuration function from the package and override only some of its
configuration statements within the code that does the include.  No conflicts
will be generated by configuration statements within the code that does the
including, even if configuration statements in the included code would
conflict if it was moved "up" to the calling code.
including, even if configuration statements in the included code would conflict
if it was moved "up" to the calling code.
Methods Which Provide Conflict Detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -312,9 +310,9 @@
:meth:`~pyramid.config.Configurator.add_resource_url_adapter`,
and :meth:`~pyramid.config.Configurator.add_response_adapter`.
:meth:`~pyramid.config.Configurator.add_static_view` also indirectly
provides conflict detection, because it's implemented in terms of the
conflict-aware ``add_route`` and ``add_view`` methods.
:meth:`~pyramid.config.Configurator.add_static_view` also indirectly provides
conflict detection, because it's implemented in terms of the conflict-aware
``add_route`` and ``add_view`` methods.
.. index::
   pair: configuration; including from external sources
@@ -324,10 +322,10 @@
Including Configuration from External Sources
---------------------------------------------
Some application programmers will factor their configuration code in such a
way that it is easy to reuse and override configuration statements.  For
example, such a developer might factor out a function used to add routes to
his application:
Some application programmers will factor their configuration code in such a way
that it is easy to reuse and override configuration statements.  For example,
such a developer might factor out a function used to add routes to their
application:
.. code-block:: python
   :linenos:
@@ -335,8 +333,8 @@
   def add_routes(config):
       config.add_route(...)
Rather than calling this function directly with ``config`` as an argument.
Instead, use :meth:`pyramid.config.Configurator.include`:
Rather than calling this function directly with ``config`` as an argument,
instead use :meth:`pyramid.config.Configurator.include`:
.. code-block:: python
   :linenos:
@@ -363,21 +361,21 @@
:meth:`~pyramid.config.Configurator.include` can also accept a :term:`dotted
Python name` to a function or a module.
.. note: See :ref:`the_include_tag` for a declarative alternative to
   the :meth:`~pyramid.config.Configurator.include` method.
.. note:: See :ref:`the_include_tag` for a declarative alternative to the
   :meth:`~pyramid.config.Configurator.include` method.
.. _twophase_config:
Two-Phase Configuration
-----------------------
When a non-autocommitting :term:`Configurator` is used to do configuration
(the default), configuration execution happens in two phases.  In the first
phase, "eager" configuration actions (actions that must happen before all
others, such as registering a renderer) are executed, and *discriminators*
are computed for each of the actions that depend on the result of the eager
actions.  In the second phase, the discriminators of all actions are compared
to do conflict detection.
When a non-autocommitting :term:`Configurator` is used to do configuration (the
default), configuration execution happens in two phases.  In the first phase,
"eager" configuration actions (actions that must happen before all others, such
as registering a renderer) are executed, and *discriminators* are computed for
each of the actions that depend on the result of the eager actions.  In the
second phase, the discriminators of all actions are compared to do conflict
detection.
Due to this, for configuration methods that have no internal ordering
constraints, execution order of configuration method calls is not important.
@@ -401,15 +399,14 @@
   config.add_view('some.view', renderer='path_to_custom/renderer.rn')
Even though the view statement depends on the registration of a custom
renderer, due to two-phase configuration, the order in which the
configuration statements are issued is not important.  ``add_view`` will be
able to find the ``.rn`` renderer even if ``add_renderer`` is called after
``add_view``.
renderer, due to two-phase configuration, the order in which the configuration
statements are issued is not important.  ``add_view`` will be able to find the
``.rn`` renderer even if ``add_renderer`` is called after ``add_view``.
The same is untrue when you use an *autocommitting* configurator (see
:ref:`autocommitting_configurator`).  When an autocommitting configurator is
used, two-phase configuration is disabled, and configuration statements must
be ordered in dependency order.
used, two-phase configuration is disabled, and configuration statements must be
ordered in dependency order.
Some configuration methods, such as
:meth:`~pyramid.config.Configurator.add_route` have internal ordering
@@ -420,7 +417,7 @@
More Information
----------------
For more information, see the article, `"A Whirlwind Tour of Advanced
For more information, see the article `"A Whirlwind Tour of Advanced
Configuration Tactics"
<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_,
<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_
in the Pyramid Cookbook.
docs/narr/commandline.rst
@@ -107,9 +107,7 @@
.. index::
   single: interactive shell
   single: IPython
   single: pshell
   single: bpython
.. _interactive_shell:
@@ -263,38 +261,42 @@
    >>> request.route_url('home')
    'https://www.example.com/'
.. index::
   single: IPython
   single: bpython
.. _ipython_or_bpython:
IPython or bpython
~~~~~~~~~~~~~~~~~~
If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ and/or `bpython
<http://bpython-interpreter.org/>`_ in the interpreter you use to invoke the
``pshell`` command, ``pshell`` will autodiscover and use the first one found,
in this order: IPython, bpython, standard Python interpreter. However you could
specifically invoke your choice with the ``-p choice`` or ``--python-shell
choice`` option.
.. code-block:: text
   $ $VENV/bin/pshell -p ipython | bpython | python development.ini#MyProject
Alternative Shells
~~~~~~~~~~~~~~~~~~
The ``pshell`` command can be easily extended with alternate REPLs if the
default python REPL is not satisfactory. Assuming you have a binding
installed such as ``pyramid_ipython`` it will normally be auto-selected and
used. You may also specifically invoke your choice with the ``-p choice`` or
``--python-shell choice`` option.
.. code-block:: text
   $ $VENV/bin/pshell -p ipython development.ini#MyProject
You may use the ``--list-shells`` option to see the available shells.
.. code-block:: text
   $ $VENV/bin/pshell --list-shells
   Available shells:
     bpython
     ipython
     python
If you want to use a shell that isn't supported out of the box, you can
introduce a new shell by registering an entry point in your setup.py:
.. code-block:: python
    setup(
        entry_points = """\
            [pyramid.pshell]
            myshell=my_app:ptpython_shell_factory
        """
        entry_points={
            'pyramid.pshell_runner': [
              'myshell=my_app:ptpython_shell_factory',
            ],
        },
    )
And then your shell factory should return a function that accepts two
@@ -302,16 +304,30 @@
.. code-block:: python
    def ptpython_shell_factory():
        from ptpython.repl import embed
        def PTPShell(banner, **kwargs):
            print(banner)
            return embed(**kwargs)
    from ptpython.repl import embed
        def shell(env, help):
            PTPShell(banner=help, locals=env)
    def ptpython_shell_runner(env, help):
        print(help)
        return embed(locals=env)
        return shell
.. versionchanged:: 1.6
   User-defined shells may be registered using entry points. Prior to this
   the only supported shells were ``ipython``, ``bpython`` and ``python``.
   ``ipython`` and ``bpython`` have been moved into their respective
   packages ``pyramid_ipython`` and ``pyramid_bpython``.
Setting a Default Shell
~~~~~~~~~~~~~~~~~~~~~~~
You may use the ``default_shell`` option in your ``[pshell]`` ini section to
specify a list of preferred shells.
.. code-block:: ini
   :linenos:
   [pshell]
   default_shell = ptpython ipython bpython
.. versionadded:: 1.6
docs/narr/extconfig.rst
@@ -7,9 +7,9 @@
===============================
Pyramid allows you to extend its Configurator with custom directives.  Custom
directives can use other directives, they can add a custom :term:`action`,
they can participate in :term:`conflict resolution`, and they can provide
some number of :term:`introspectable` objects.
directives can use other directives, they can add a custom :term:`action`, they
can participate in :term:`conflict resolution`, and they can provide some
number of :term:`introspectable` objects.
.. index::
   single: add_directive
@@ -20,18 +20,17 @@
Adding Methods to the Configurator via ``add_directive``
--------------------------------------------------------
Framework extension writers can add arbitrary methods to a
:term:`Configurator` by using the
:meth:`pyramid.config.Configurator.add_directive` method of the configurator.
Using :meth:`~pyramid.config.Configurator.add_directive` makes it possible to
extend a Pyramid configurator in arbitrary ways, and allows it to perform
application-specific tasks more succinctly.
Framework extension writers can add arbitrary methods to a :term:`Configurator`
by using the :meth:`pyramid.config.Configurator.add_directive` method of the
configurator. Using :meth:`~pyramid.config.Configurator.add_directive` makes it
possible to extend a Pyramid configurator in arbitrary ways, and allows it to
perform application-specific tasks more succinctly.
The :meth:`~pyramid.config.Configurator.add_directive` method accepts two
positional arguments: a method name and a callable object.  The callable
object is usually a function that takes the configurator instance as its
first argument and accepts other arbitrary positional and keyword arguments.
For example:
positional arguments: a method name and a callable object.  The callable object
is usually a function that takes the configurator instance as its first
argument and accepts other arbitrary positional and keyword arguments. For
example:
.. code-block:: python
   :linenos:
@@ -48,8 +47,8 @@
                            add_newrequest_subscriber)
Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can
then call the added directive by its given name as if it were a built-in
method of the Configurator:
then call the added directive by its given name as if it were a built-in method
of the Configurator:
.. code-block:: python
   :linenos:
@@ -59,9 +58,9 @@
   config.add_newrequest_subscriber(mysubscriber)
A call to :meth:`~pyramid.config.Configurator.add_directive` is often
"hidden" within an ``includeme`` function within a "frameworky" package meant
to be included as per :ref:`including_configuration` via
A call to :meth:`~pyramid.config.Configurator.add_directive` is often "hidden"
within an ``includeme`` function within a "frameworky" package meant to be
included as per :ref:`including_configuration` via
:meth:`~pyramid.config.Configurator.include`.  For example, if you put this
code in a package named ``pyramid_subscriberhelpers``:
@@ -72,8 +71,8 @@
       config.add_directive('add_newrequest_subscriber',
                            add_newrequest_subscriber)
The user of the add-on package ``pyramid_subscriberhelpers`` would then be
able to install it and subsequently do:
The user of the add-on package ``pyramid_subscriberhelpers`` would then be able
to install it and subsequently do:
.. code-block:: python
   :linenos:
@@ -91,13 +90,12 @@
If a custom directive can't do its work exclusively in terms of existing
configurator methods (such as
:meth:`pyramid.config.Configurator.add_subscriber`, as above), the directive
may need to make use of the :meth:`pyramid.config.Configurator.action`
method.  This method adds an entry to the list of "actions" that Pyramid will
attempt to process when :meth:`pyramid.config.Configurator.commit` is called.
An action is simply a dictionary that includes a :term:`discriminator`,
possibly a callback function, and possibly other metadata used by Pyramid's
action system.
:meth:`pyramid.config.Configurator.add_subscriber` as above), the directive may
need to make use of the :meth:`pyramid.config.Configurator.action` method. This
method adds an entry to the list of "actions" that Pyramid will attempt to
process when :meth:`pyramid.config.Configurator.commit` is called. An action is
simply a dictionary that includes a :term:`discriminator`, possibly a callback
function, and possibly other metadata used by Pyramid's action system.
Here's an example directive which uses the "action" method:
@@ -122,15 +120,15 @@
When the :meth:`~pyramid.config.Configurator.action` method is called, it
appends an action to the list of pending configuration actions.  All pending
actions with the same discriminator value are potentially in conflict with
one another (see :ref:`conflict_detection`).  When the
actions with the same discriminator value are potentially in conflict with one
another (see :ref:`conflict_detection`).  When the
:meth:`~pyramid.config.Configurator.commit` method of the Configurator is
called (either explicitly or as the result of calling
:meth:`~pyramid.config.Configurator.make_wsgi_app`), conflicting actions are
potentially automatically resolved as per
:ref:`automatic_conflict_resolution`.  If a conflict cannot be automatically
resolved, a :exc:`pyramid.exceptions.ConfigurationConflictError` is raised
and application startup is prevented.
potentially automatically resolved as per :ref:`automatic_conflict_resolution`.
If a conflict cannot be automatically resolved, a
:exc:`pyramid.exceptions.ConfigurationConflictError` is raised and application
startup is prevented.
In our above example, therefore, if a consumer of our ``add_jammyjam``
directive did this:
@@ -146,14 +144,14 @@
resolution cannot resolve the conflict (because no ``config.include`` is
involved), and the user provided no intermediate
:meth:`pyramid.config.Configurator.commit` call between the calls to
``add_jammyjam`` to ensure that the successive calls did not conflict with
each other.
``add_jammyjam`` to ensure that the successive calls did not conflict with each
other.
This demonstrates the purpose of the discriminator argument to the action
method: it's used to indicate a uniqueness constraint for an action.  Two
actions with the same discriminator will conflict unless the conflict is
automatically or manually resolved. A discriminator can be any hashable
object, but it is generally a string or a tuple.  *You use a discriminator to
automatically or manually resolved. A discriminator can be any hashable object,
but it is generally a string or a tuple.  *You use a discriminator to
declaratively ensure that the user doesn't provide ambiguous configuration
statements.*
@@ -169,21 +167,20 @@
are processed during :meth:`~pyramid.config.Configurator.commit`, and no
conflicts occur, the *callable* provided as the second argument to the
:meth:`~pyramid.config.Configurator.action` method within ``add_jammyjam`` is
called with no arguments.  The callable in ``add_jammyjam`` is the
``register`` closure function.  It simply sets the value
``config.registry.jammyjam`` to whatever the user passed in as the
``jammyjam`` argument to the ``add_jammyjam`` function.  Therefore, the
result of the user's call to our directive will set the ``jammyjam``
attribute of the registry to the string ``first``.  *A callable is used by a
directive to defer the result of a user's call to the directive until
conflict detection has had a chance to do its job*.
called with no arguments.  The callable in ``add_jammyjam`` is the ``register``
closure function.  It simply sets the value ``config.registry.jammyjam`` to
whatever the user passed in as the ``jammyjam`` argument to the
``add_jammyjam`` function.  Therefore, the result of the user's call to our
directive will set the ``jammyjam`` attribute of the registry to the string
``first``.  *A callable is used by a directive to defer the result of a user's
call to the directive until conflict detection has had a chance to do its job*.
Other arguments exist to the :meth:`~pyramid.config.Configurator.action`
method, including ``args``, ``kw``, ``order``, and ``introspectables``.
method, including ``args``, ``kw``, ``order``, and ``introspectables``.
``args`` and ``kw`` exist as values, which, if passed, will be used as
arguments to the ``callable`` function when it is called back.  For example
our directive might use them like so:
``args`` and ``kw`` exist as values, which if passed will be used as arguments
to the ``callable`` function when it is called back.  For example, our
directive might use them like so:
.. code-block:: python
   :linenos:
@@ -198,31 +195,33 @@
In the above example, when this directive is used to generate an action, and
that action is committed, ``config.registry.jammyjam_args`` will be set to
``('one',)`` and ``config.registry.jammyjam_kw`` will be set to
``{'two':'two'}``.  ``args`` and ``kw`` are honestly not very useful when
your ``callable`` is a closure function, because you already usually have
access to every local in the directive without needing them to be passed
back.  They can be useful, however, if you don't use a closure as a callable.
``{'two':'two'}``.  ``args`` and ``kw`` are honestly not very useful when your
``callable`` is a closure function, because you already usually have access to
every local in the directive without needing them to be passed back.  They can
be useful, however, if you don't use a closure as a callable.
``order`` is a crude order control mechanism.  ``order`` defaults to the
integer ``0``; it can be set to any other integer.  All actions that share an
order will be called before other actions that share a higher order.  This
makes it possible to write a directive with callable logic that relies on the
execution of the callable of another directive being done first.  For
example, Pyramid's :meth:`pyramid.config.Configurator.add_view` directive
registers an action with a higher order than the
execution of the callable of another directive being done first.  For example,
Pyramid's :meth:`pyramid.config.Configurator.add_view` directive registers an
action with a higher order than the
:meth:`pyramid.config.Configurator.add_route` method.  Due to this, the
``add_view`` method's callable can assume that, if a ``route_name`` was
passed to it, that a route by this name was already registered by
``add_route``, and if such a route has not already been registered, it's a
configuration error (a view that names a nonexistent route via its
``route_name`` parameter will never be called). As of Pyramid 1.6 it is
possible for one action to invoke another. See :ref:`ordering_actions` for
more information.
``add_view`` method's callable can assume that, if a ``route_name`` was passed
to it, that a route by this name was already registered by ``add_route``, and
if such a route has not already been registered, it's a configuration error (a
view that names a nonexistent route via its ``route_name`` parameter will never
be called).
``introspectables`` is a sequence of :term:`introspectable` objects.  You can
pass a sequence of introspectables to the
:meth:`~pyramid.config.Configurator.action` method, which allows you to
augment Pyramid's configuration introspection system.
.. versionchanged:: 1.6
  As of Pyramid 1.6 it is possible for one action to invoke another. See
  :ref:`ordering_actions` for more information.
Finally, ``introspectables`` is a sequence of :term:`introspectable` objects.
You can pass a sequence of introspectables to the
:meth:`~pyramid.config.Configurator.action` method, which allows you to augment
Pyramid's configuration introspection system.
.. _ordering_actions:
@@ -233,18 +232,17 @@
actions. The logic within actions is deferred until a call to
:meth:`pyramid.config.Configurator.commit` (which is automatically invoked by
:meth:`pyramid.config.Configurator.make_wsgi_app`). This means you may call
``config.add_view(route_name='foo')`` **before**
``config.add_route('foo', '/foo')`` because nothing actually happens until
commit-time. During a commit cycle conflicts are resolved, actions are ordered
and executed.
``config.add_view(route_name='foo')`` **before** ``config.add_route('foo',
'/foo')`` because nothing actually happens until commit-time. During a commit
cycle, conflicts are resolved, and actions are ordered and executed.
By default, almost every action in Pyramid has an ``order`` of
:const:`pyramid.config.PHASE3_CONFIG`. Every action within the same order-level
will be executed in the order it was called.
This means that if an action must be reliably executed before or after another
action, the ``order`` must be defined explicitly to make this work. For
example, views are dependent on routes being defined. Thus the action created
by :meth:`pyramid.config.Configurator.add_route` has an ``order`` of
will be executed in the order it was called. This means that if an action must
be reliably executed before or after another action, the ``order`` must be
defined explicitly to make this work. For example, views are dependent on
routes being defined. Thus the action created by
:meth:`pyramid.config.Configurator.add_route` has an ``order`` of
:const:`pyramid.config.PHASE2_CONFIG`.
Pre-defined Phases
@@ -252,8 +250,8 @@
:const:`pyramid.config.PHASE0_CONFIG`
- This phase is reserved for developers who want to execute actions prior
  to Pyramid's core directives.
- This phase is reserved for developers who want to execute actions prior to
  Pyramid's core directives.
:const:`pyramid.config.PHASE1_CONFIG`
@@ -274,17 +272,17 @@
- The default for all builtin or custom directives unless otherwise specified.
Calling Actions From Actions
Calling Actions from Actions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.6
Pyramid's configurator allows actions to be added during a commit-cycle as
long as they are added to the current or a later ``order`` phase. This means
that your custom action can defer decisions until commit-time and then do
things like invoke :meth:`pyramid.config.Configurator.add_route`. It can also
provide better conflict detection if your addon needs to call more than one
other action.
Pyramid's configurator allows actions to be added during a commit-cycle as long
as they are added to the current or a later ``order`` phase. This means that
your custom action can defer decisions until commit-time and then do things
like invoke :meth:`pyramid.config.Configurator.add_route`. It can also provide
better conflict detection if your addon needs to call more than one other
action.
For example, let's make an addon that invokes ``add_route`` and ``add_view``,
but we want it to conflict with any other call to our addon:
@@ -304,12 +302,12 @@
       config.action(('auto route', name), register, order=PHASE0_CONFIG)
Now someone else can use your addon and be informed if there is a conflict
between this route and another, or two calls to ``add_auto_route``.
Notice how we had to invoke our action **before** ``add_view`` or
``add_route``. If we tried to invoke this afterward, the subsequent calls to
``add_view`` and ``add_route`` would cause conflicts because that phase had
already been executed, and the configurator cannot go back in time to add more
views during that commit-cycle.
between this route and another, or two calls to ``add_auto_route``. Notice how
we had to invoke our action **before** ``add_view`` or ``add_route``. If we
tried to invoke this afterward, the subsequent calls to ``add_view`` and
``add_route`` would cause conflicts because that phase had already been
executed, and the configurator cannot go back in time to add more views during
that commit-cycle.
.. code-block:: python
   :linenos:
@@ -341,16 +339,16 @@
introspectables when called.  For example, when you register a view via
``add_view``, the directive registers at least one introspectable: an
introspectable about the view registration itself, providing human-consumable
values for the arguments it was passed.  You can later use the introspection
query system to determine whether a particular view uses a renderer, or
whether a particular view is limited to a particular request method, or which
routes a particular view is registered against.  The Pyramid "debug toolbar"
makes use of the introspection system in various ways to display information
to Pyramid developers.
values for the arguments passed into it.  You can later use the introspection
query system to determine whether a particular view uses a renderer, or whether
a particular view is limited to a particular request method, or against which
routes a particular view is registered.  The Pyramid "debug toolbar" makes use
of the introspection system in various ways to display information to Pyramid
developers.
Introspection values are set when a sequence of :term:`introspectable`
objects is passed to the :meth:`~pyramid.config.Configurator.action` method.
Here's an example of a directive which uses introspectables:
Introspection values are set when a sequence of :term:`introspectable` objects
is passed to the :meth:`~pyramid.config.Configurator.action` method. Here's an
example of a directive which uses introspectables:
.. code-block:: python
   :linenos:
@@ -370,9 +368,9 @@
       config.add_directive('add_jammyjam', add_jammyjam)
If you notice, the above directive uses the ``introspectable`` attribute of a
Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create
an introspectable object.  The introspectable object's constructor requires
at least four arguments: the ``category_name``, the ``discriminator``, the
Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create an
introspectable object.  The introspectable object's constructor requires at
least four arguments: the ``category_name``, the ``discriminator``, the
``title``, and the ``type_name``.
The ``category_name`` is a string representing the logical category for this
@@ -392,19 +390,19 @@
within its category for sorting and presentation purposes.  It can be any
value.
An introspectable is also dictionary-like.  It can contain any set of
key/value pairs, typically related to the arguments passed to its related
directive.  While the category_name, discriminator, title and type_name are
*metadata* about the introspectable, the values provided as key/value pairs
An introspectable is also dictionary-like.  It can contain any set of key/value
pairs, typically related to the arguments passed to its related directive.
While the ``category_name``, ``discriminator``, ``title``, and ``type_name``
are *metadata* about the introspectable, the values provided as key/value pairs
are the actual data provided by the introspectable.  In the above example, we
set the ``value`` key to the value of the ``value`` argument passed to the
directive.
Our directive above mutates the introspectable, and passes it in to the
``action`` method as the first element of a tuple as the value of the
``introspectable`` keyword argument.  This associates this introspectable
with the action.  Introspection tools will then display this introspectable
in their index.
``introspectable`` keyword argument.  This associates this introspectable with
the action.  Introspection tools will then display this introspectable in their
index.
Introspectable Relationships
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -435,30 +433,29 @@
       config.add_directive('add_jammyjam', add_jammyjam)
In the above example, the ``add_jammyjam`` directive registers two
introspectables.  The first is related to the ``value`` passed to the
directive; the second is related to the ``template`` passed to the directive.
If you believe a concept within a directive is important enough to have its
own introspectable, you can cause the same directive to register more than
one introspectable, registering one introspectable for the "main idea" and
another for a related concept.
introspectables: the first is related to the ``value`` passed to the directive,
and the second is related to the ``template`` passed to the directive. If you
believe a concept within a directive is important enough to have its own
introspectable, you can cause the same directive to register more than one
introspectable, registering one introspectable for the "main idea" and another
for a related concept.
The call to ``intr.relate`` above
(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments:
a category name and a directive.  The example above effectively indicates
that the directive wishes to form a relationship between the ``intr``
introspectable and the ``tmpl_intr`` introspectable; the arguments passed to
``relate`` are the category name and discriminator of the ``tmpl_intr``
introspectable.
(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments: a
category name and a directive.  The example above effectively indicates that
the directive wishes to form a relationship between the ``intr`` introspectable
and the ``tmpl_intr`` introspectable; the arguments passed to ``relate`` are
the category name and discriminator of the ``tmpl_intr`` introspectable.
Relationships need not be made between two introspectables created by the
same directive.  Instead, a relationship can be formed between an
introspectable created in one directive and another introspectable created in
another by calling ``relate`` on either side with the other directive's
category name and discriminator.  An error will be raised at configuration
commit time if you attempt to relate an introspectable with another
nonexistent introspectable, however.
Relationships need not be made between two introspectables created by the same
directive.  Instead a relationship can be formed between an introspectable
created in one directive and another introspectable created in another by
calling ``relate`` on either side with the other directive's category name and
discriminator.  An error will be raised at configuration commit time if you
attempt to relate an introspectable with another nonexistent introspectable,
however.
Introspectable relationships will show up in frontend system renderings of
introspection values.  For example, if a view registration names a route
name, the introspectable related to the view callable will show a reference
to the route to which it relates to and vice versa.
introspection values.  For example, if a view registration names a route name,
the introspectable related to the view callable will show a reference to the
route to which it relates and vice versa.
docs/narr/extending.rst
@@ -1,13 +1,13 @@
.. _extending_chapter:
Extending An Existing :app:`Pyramid` Application
===================================================
Extending an Existing :app:`Pyramid` Application
================================================
If a :app:`Pyramid` developer has obeyed certain constraints while building
an application, a third party should be able to change the application's
behavior without needing to modify its source code.  The behavior of a
:app:`Pyramid` application that obeys certain constraints can be *overridden*
or *extended* without modification.
If a :app:`Pyramid` developer has obeyed certain constraints while building an
application, a third party should be able to change the application's behavior
without needing to modify its source code.  The behavior of a :app:`Pyramid`
application that obeys certain constraints can be *overridden* or *extended*
without modification.
We'll define some jargon here for the benefit of identifying the parties
involved in such an effort.
@@ -16,10 +16,10 @@
  The original application developer.
Integrator
  Another developer who wishes to reuse the application written by the
  original application developer in an unanticipated context.  He may also
  wish to modify the original application without changing the original
  application's source code.
  Another developer who wishes to reuse the application written by the original
  application developer in an unanticipated context.  They may also wish to
  modify the original application without changing the original application's
  source code.
The Difference Between "Extensible" and "Pluggable" Applications
----------------------------------------------------------------
@@ -27,31 +27,31 @@
Other web frameworks, such as :term:`Django`, advertise that they allow
developers to create "pluggable applications".  They claim that if you create
an application in a certain way, it will be integratable in a sensible,
structured way into another arbitrarily-written application or project
created by a third-party developer.
structured way into another arbitrarily-written application or project created
by a third-party developer.
:app:`Pyramid`, as a platform, does not claim to provide such a feature.  The
platform provides no guarantee that you can create an application and package
it up such that an arbitrary integrator can use it as a subcomponent in a
larger Pyramid application or project.  Pyramid does not mandate the
constraints necessary for such a pattern to work satisfactorily.  Because
Pyramid is not very "opinionated", developers are able to use wildly
different patterns and technologies to build an application.  A given Pyramid
application may happen to be reusable by a particular third party integrator,
because the integrator and the original developer may share similar base
technology choices (such as the use of a particular relational database or
ORM).  But the same application may not be reusable by a different developer,
because he has made different technology choices which are incompatible with
the original developer's.
Pyramid is not very "opinionated", developers are able to use wildly different
patterns and technologies to build an application.  A given Pyramid application
may happen to be reusable by a particular third party integrator because the
integrator and the original developer may share similar base technology choices
(such as the use of a particular relational database or ORM).  But the same
application may not be reusable by a different developer, because they have
made different technology choices which are incompatible with the original
developer's.
As a result, the concept of a "pluggable application" is left to layers built
above Pyramid, such as a "CMS" layer or "application server" layer.  Such
layers are apt to provide the necessary "opinions" (such as mandating a
storage layer, a templating system, and a structured, well-documented pattern
of registering that certain URLs map to certain bits of code) which makes the
concept of a "pluggable application" possible.  "Pluggable applications",
thus, should not plug into Pyramid itself but should instead plug into a
system written atop Pyramid.
layers are apt to provide the necessary "opinions" (such as mandating a storage
layer, a templating system, and a structured, well-documented pattern of
registering that certain URLs map to certain bits of code) which makes the
concept of a "pluggable application" possible.  "Pluggable applications", thus,
should not plug into Pyramid itself but should instead plug into a system
written atop Pyramid.
Although it does not provide for "pluggable applications", Pyramid *does*
provide a rich set of mechanisms which allows for the extension of a single
@@ -64,13 +64,13 @@
.. _building_an_extensible_app:
Rules for Building An Extensible Application
Rules for Building an Extensible Application
--------------------------------------------
There is only one rule you need to obey if you want to build a maximally
extensible :app:`Pyramid` application: as a developer, you should factor any
overrideable :term:`imperative configuration` you've created into functions
which can be used via :meth:`pyramid.config.Configurator.include` rather than
overridable :term:`imperative configuration` you've created into functions
which can be used via :meth:`pyramid.config.Configurator.include`, rather than
inlined as calls to methods of a :term:`Configurator` within the ``main``
function in your application's ``__init__.py``.  For example, rather than:
@@ -84,8 +84,8 @@
       config.add_view('myapp.views.view1', name='view1')
       config.add_view('myapp.views.view2', name='view2')
You should move the calls to ``add_view`` outside of the (non-reusable)
``if __name__ == '__main__'`` block, and into a reusable function:
You should move the calls to ``add_view`` outside of the (non-reusable) ``if
__name__ == '__main__'`` block, and into a reusable function:
.. code-block:: python
   :linenos:
@@ -100,13 +100,12 @@
       config.add_view('myapp.views.view1', name='view1')
       config.add_view('myapp.views.view2', name='view2')
Doing this allows an integrator to maximally reuse the configuration
statements that relate to your application by allowing him to selectively
include or disinclude the configuration functions you've created from an
"override package".
Doing this allows an integrator to maximally reuse the configuration statements
that relate to your application by allowing them to selectively include or
exclude the configuration functions you've created from an "override package".
Alternately, you can use :term:`ZCML` for the purpose of making configuration
extensible and overrideable. :term:`ZCML` declarations that belong to an
Alternatively you can use :term:`ZCML` for the purpose of making configuration
extensible and overridable. :term:`ZCML` declarations that belong to an
application can be overridden and extended by integrators as necessary in a
similar fashion.  If you use only :term:`ZCML` to configure your application,
it will automatically be maximally extensible without any manual effort.  See
@@ -115,16 +114,15 @@
Fundamental Plugpoints
~~~~~~~~~~~~~~~~~~~~~~
The fundamental "plug points" of an application developed using
:app:`Pyramid` are *routes*, *views*, and *assets*.  Routes are declarations
made using the :meth:`pyramid.config.Configurator.add_route` method.  Views
are declarations made using the :meth:`pyramid.config.Configurator.add_view`
method.  Assets are files that are
accessed by :app:`Pyramid` using the :term:`pkg_resources` API such as static
files and templates via a :term:`asset specification`.  Other directives and
configurator methods also deal in routes, views, and assets.  For example, the
``add_handler`` directive of the ``pyramid_handlers`` package adds a single
route, and some number of views.
The fundamental "plug points" of an application developed using :app:`Pyramid`
are *routes*, *views*, and *assets*.  Routes are declarations made using the
:meth:`pyramid.config.Configurator.add_route` method.  Views are declarations
made using the :meth:`pyramid.config.Configurator.add_view` method.  Assets are
files that are accessed by :app:`Pyramid` using the :term:`pkg_resources` API
such as static files and templates via a :term:`asset specification`.  Other
directives and configurator methods also deal in routes, views, and assets.
For example, the ``add_handler`` directive of the ``pyramid_handlers`` package
adds a single route and some number of views.
.. index::
   single: extending an existing application
@@ -133,10 +131,9 @@
---------------------------------
The steps for extending an existing application depend largely on whether the
application does or does not use configuration decorators and/or imperative
code.
application does or does not use configuration decorators or imperative code.
If The Application Has Configuration Decorations
If the Application Has Configuration Decorations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You've inherited a :app:`Pyramid` application which you'd like to extend or
@@ -155,9 +152,9 @@
       config.add_view('mypackage.views.myview', name='myview')
If you want to *override* configuration in the application, you *may* need to
run :meth:`pyramid.config.Configurator.commit` after performing the scan of
the original package, then add additional configuration that registers more
views or routes which performs overrides.
run :meth:`pyramid.config.Configurator.commit` after performing the scan of the
original package, then add additional configuration that registers more views
or routes which perform overrides.
.. code-block:: python
   :linenos:
@@ -170,11 +167,11 @@
Once this is done, you should be able to extend or override the application
like any other (see :ref:`extending_the_application`).
You can alternately just prevent a :term:`scan` from happening (by omitting
any call to the :meth:`pyramid.config.Configurator.scan` method).  This will
You can alternatively just prevent a :term:`scan` from happening by omitting
any call to the :meth:`pyramid.config.Configurator.scan` method.  This will
cause the decorators attached to objects in the target application to do
nothing.  At this point, you will need to convert all the configuration done
in decorators into equivalent imperative configuration or ZCML and add that
nothing.  At this point, you will need to convert all the configuration done in
decorators into equivalent imperative configuration or ZCML, and add that
configuration or ZCML to a separate Python package as described in
:ref:`extending_the_application`.
@@ -183,37 +180,37 @@
Extending the Application
~~~~~~~~~~~~~~~~~~~~~~~~~
To extend or override the behavior of an existing application, you will need
to create a new package which includes the configuration of the old package,
and you'll perhaps need to create implementations of the types of things
you'd like to override (such as views), which are referred to within the
original package.
To extend or override the behavior of an existing application, you will need to
create a new package which includes the configuration of the old package, and
you'll perhaps need to create implementations of the types of things you'd like
to override (such as views), to which they are referred within the original
package.
The general pattern for extending an existing application looks something
like this:
The general pattern for extending an existing application looks something like
this:
- Create a new Python package.  The easiest way to do this is to create a new
  :app:`Pyramid` application using the scaffold mechanism.  See
  :ref:`creating_a_project` for more information.
- In the new package, create Python files containing views and other
  overridden elements, such as templates and static assets as necessary.
- In the new package, create Python files containing views and other overridden
  elements, such as templates and static assets as necessary.
- Install the new package into the same Python environment as the original
  application (e.g. ``$VENV/bin/python setup.py develop`` or
  application (e.g., ``$VENV/bin/python setup.py develop`` or
  ``$VENV/bin/python setup.py install``).
- Change the ``main`` function in the new package's ``__init__.py`` to include
  the original :app:`Pyramid` application's configuration functions via
  :meth:`pyramid.config.Configurator.include` statements or a :term:`scan`.
- Wire the new views and assets created in the new package up using
  imperative registrations within the ``main`` function of the
  ``__init__.py`` file of the new application.  This wiring should happen
  *after* including the configuration functions of the old application.
  These registrations will extend or override any registrations performed by
  the original application.  See :ref:`overriding_views`,
  :ref:`overriding_routes` and :ref:`overriding_resources`.
- Wire the new views and assets created in the new package up using imperative
  registrations within the ``main`` function of the ``__init__.py`` file of the
  new application.  This wiring should happen *after* including the
  configuration functions of the old application.  These registrations will
  extend or override any registrations performed by the original application.
  See :ref:`overriding_views`, :ref:`overriding_routes`, and
  :ref:`overriding_resources`.
.. index::
   pair: overriding; views
@@ -221,17 +218,17 @@
.. _overriding_views:
Overriding Views
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~
The :term:`view configuration` declarations you make which *override*
The :term:`view configuration` declarations that you make which *override*
application behavior will usually have the same :term:`view predicate`
attributes as the original you wish to override.  These ``<view>``
declarations will point at "new" view code, in the override package you've
created.  The new view code itself will usually be cut-n-paste copies of view
callables from the original application with slight tweaks.
attributes as the original that you wish to override.  These ``<view>``
declarations will point at "new" view code in the override package that you've
created.  The new view code itself will usually be copy-and-paste copies of
view callables from the original application with slight tweaks.
For example, if the original application has the following
``configure_views`` configuration method:
For example, if the original application has the following ``configure_views``
configuration method:
.. code-block:: python
    :linenos:
@@ -254,13 +251,13 @@
       config.include(configure_views)
       config.add_view('theoverrideapp.views.theview', name='theview')
In this case, the ``theoriginalapp.views.theview`` view will never be
executed.  Instead, a new view, ``theoverrideapp.views.theview`` will be
executed instead, when request circumstances dictate.
In this case, the ``theoriginalapp.views.theview`` view will never be executed.
Instead, a new view, ``theoverrideapp.views.theview`` will be executed when
request circumstances dictate.
A similar pattern can be used to *extend* the application with ``add_view``
declarations.  Just register a new view against some other set of predicates
to make sure the URLs it implies are available on some other page rendering.
declarations.  Just register a new view against some other set of predicates to
make sure the URLs it implies are available on some other page rendering.
.. index::
   pair: overriding; routes
@@ -270,13 +267,13 @@
Overriding Routes
~~~~~~~~~~~~~~~~~
Route setup is currently typically performed in a sequence of ordered calls
to :meth:`~pyramid.config.Configurator.add_route`.  Because these calls are
Route setup is currently typically performed in a sequence of ordered calls to
:meth:`~pyramid.config.Configurator.add_route`.  Because these calls are
ordered relative to each other, and because this ordering is typically
important, you should retain their relative ordering when performing an
override.  Typically, this means *copying* all the ``add_route`` statements
into the override package's file and changing them as necessary.  Then
disinclude any ``add_route`` statements from the original application.
override.  Typically this means *copying* all the ``add_route`` statements into
the override package's file and changing them as necessary.  Then exclude any
``add_route`` statements from the original application.
.. index::
   pair: overriding; assets
@@ -288,9 +285,8 @@
Assets are files on the filesystem that are accessible within a Python
*package*.  An entire chapter is devoted to assets: :ref:`assets_chapter`.
Within this chapter is a section named :ref:`overriding_assets_section`.
This section of that chapter describes in detail how to override package
assets with other assets by using the
:meth:`pyramid.config.Configurator.override_asset` method.  Add such
``override_asset`` calls to your override package's ``__init__.py`` to
perform overrides.
Within this chapter is a section named :ref:`overriding_assets_section`. This
section of that chapter describes in detail how to override package assets with
other assets by using the :meth:`pyramid.config.Configurator.override_asset`
method.  Add such ``override_asset`` calls to your override package's
``__init__.py`` to perform overrides.
docs/narr/hellotraversal.rst
@@ -1,64 +1,60 @@
.. _hello_traversal_chapter:
Hello Traversal World
======================
=====================
.. index::
   single: traversal quick example
Traversal is an alternative to URL dispatch which allows Pyramid
applications to map URLs to code.
Traversal is an alternative to URL dispatch which allows Pyramid applications
to map URLs to code.
If code speaks louder than words, maybe this will help. Here is a
single-file Pyramid application that uses traversal:
If code speaks louder than words, maybe this will help. Here is a single-file
Pyramid application that uses traversal:
.. literalinclude:: hellotraversal.py
   :linenos:
You may notice that this application is intentionally very similar to
the "hello world" app from :doc:`firstapp`.
You may notice that this application is intentionally very similar to the
"hello world" application from :doc:`firstapp`.
On lines 5-6, we create a trivial :term:`resource` class that's just a
dictionary subclass.
On lines 8-9, we hard-code a :term:`resource tree` in our :term:`root
factory` function.
On lines 8-9, we hard-code a :term:`resource tree` in our :term:`root factory`
function.
On lines 11-13 we define a single :term:`view callable` that can
display a single instance of our Resource class, passed as the
``context`` argument.
On lines 11-13, we define a single :term:`view callable` that can display a
single instance of our ``Resource`` class, passed as the ``context`` argument.
The rest of the file sets up and serves our pyramid WSGI app.  Line 18
is where our view gets configured for use whenever the traversal ends
with an instance of our Resource class.
The rest of the file sets up and serves our :app:`Pyramid` WSGI app.  Line 18
is where our view gets configured for use whenever the traversal ends with an
instance of our ``Resource`` class.
Interestingly, there are no URLs explicitly configured in this
application. Instead, the URL space is defined entirely by the keys in
the resource tree.
Interestingly, there are no URLs explicitly configured in this application.
Instead, the URL space is defined entirely by the keys in the resource tree.
Example requests
----------------
If this example is running on http://localhost:8080, and the user
browses to http://localhost:8080/a/b, Pyramid will call
``get_root(request)`` to get the root resource, then traverse the tree
from there by key; starting from the root, it will find the child with
key ``"a"``, then its child with key ``"b"``; then use that as the
``context`` argument for calling ``hello_world_of_resources``.
If this example is running on http://localhost:8080, and the user browses to
http://localhost:8080/a/b, Pyramid will call ``get_root(request)`` to get the
root resource, then traverse the tree from there by key; starting from the
root, it will find the child with key ``"a"``, then its child with key ``"b"``;
then use that as the ``context`` argument for calling
``hello_world_of_resources``.
Or, if the user browses to http://localhost:8080/ , Pyramid will
stop at the root - the outermost Resource instance, in this case - and
use that as the ``context`` argument to the same view.
Or, if the user browses to http://localhost:8080/, Pyramid will stop at the
root—the outermost ``Resource`` instance, in this case—and use that as the
``context`` argument to the same view.
Or, if the user browses to a key that doesn't exist in this resource
tree, like http://localhost:8080/xyz or
http://localhost:8080/a/b/c/d, the traversal will end by raising a
KeyError, and Pyramid will turn that into a 404 HTTP response.
Or, if the user browses to a key that doesn't exist in this resource tree, like
http://localhost:8080/xyz or http://localhost:8080/a/b/c/d, the traversal will
end by raising a KeyError, and Pyramid will turn that into a 404 HTTP response.
A more complicated application could have many types of resources,
with different view callables defined for each type, and even multiple
views for each type.
A more complicated application could have many types of resources, with
different view callables defined for each type, and even multiple views for
each type.
.. seealso::
@@ -66,4 +62,3 @@
    
    For more about *why* you might use traversal, see
    :doc:`muchadoabouttraversal`.
docs/narr/hooks.rst
@@ -14,12 +14,12 @@
Changing the Not Found View
---------------------------
When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not
Found View`, which is a :term:`view callable`. The default Not Found View
can be overridden through application configuration.
When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not Found
View`, which is a :term:`view callable`. The default Not Found View can be
overridden through application configuration.
If your application uses :term:`imperative configuration`, you can replace
the Not Found View by using the
If your application uses :term:`imperative configuration`, you can replace the
Not Found View by using the
:meth:`pyramid.config.Configurator.add_notfound_view` method:
.. code-block:: python
@@ -77,14 +77,14 @@
      config = Configurator()
      config.scan()
The ``notfound_get`` view will be called when a view could not be found and
the request method was ``GET``.  The ``notfound_post`` view will be called
when a view could not be found and the request method was ``POST``.
The ``notfound_get`` view will be called when a view could not be found and the
request method was ``GET``.  The ``notfound_post`` view will be called when a
view could not be found and the request method was ``POST``.
Like any other view, the Not Found View must accept at least a ``request``
parameter, or both ``context`` and ``request``.  The ``request`` is the
current :term:`request` representing the denied action.  The ``context`` (if
used in the call signature) will be the instance of the
parameter, or both ``context`` and ``request``.  The ``request`` is the current
:term:`request` representing the denied action.  The ``context`` (if used in
the call signature) will be the instance of the
:exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the view to
be called.
@@ -106,13 +106,13 @@
.. note::
   When a Not Found View callable is invoked, it is passed a
   :term:`request`.  The ``exception`` attribute of the request will be an
   instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that
   caused the Not Found View to be called.  The value of
   ``request.exception.message`` will be a value explaining why the Not Found
   error was raised.  This message has different values depending whether the
   ``pyramid.debug_notfound`` environment setting is true or false.
   When a Not Found View callable is invoked, it is passed a :term:`request`.
   The ``exception`` attribute of the request will be an instance of the
   :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not
   Found View to be called.  The value of ``request.exception.message`` will be
   a value explaining why the Not Found exception was raised.  This message has
   different values depending on whether the ``pyramid.debug_notfound``
   environment setting is true or false.
.. note::
@@ -124,9 +124,9 @@
.. warning::
   When a Not Found View callable accepts an argument list as
   described in :ref:`request_and_context_view_definitions`, the ``context``
   passed as the first argument to the view callable will be the
   When a Not Found View callable accepts an argument list as described in
   :ref:`request_and_context_view_definitions`, the ``context`` passed as the
   first argument to the view callable will be the
   :exc:`~pyramid.httpexceptions.HTTPNotFound` exception instance.  If
   available, the resource context will still be available as
   ``request.context``.
@@ -140,13 +140,13 @@
---------------------------
When :app:`Pyramid` can't authorize execution of a view based on the
:term:`authorization policy` in use, it invokes a :term:`forbidden view`.
The default forbidden response has a 403 status code and is very plain, but
the view which generates it can be overridden as necessary.
:term:`authorization policy` in use, it invokes a :term:`forbidden view`. The
default forbidden response has a 403 status code and is very plain, but the
view which generates it can be overridden as necessary.
The :term:`forbidden view` callable is a view callable like any other.  The
:term:`view configuration` which causes it to be a "forbidden" view consists
of using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the
:term:`view configuration` which causes it to be a "forbidden" view consists of
using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the
:class:`pyramid.view.forbidden_view_config` decorator.
For example, you can add a forbidden view by using the
@@ -181,14 +181,11 @@
      config.scan()
Like any other view, the forbidden view must accept at least a ``request``
parameter, or both ``context`` and ``request``.  If a forbidden view
callable accepts both ``context`` and ``request``, the HTTP Exception is passed
as context. The ``context`` as found by the router when view was
denied (that you normally would expect) is available as
``request.context``.  The ``request`` is the  current :term:`request`
representing the denied action.
parameter, or both ``context`` and ``request``.  If a forbidden view callable
accepts both ``context`` and ``request``, the HTTP Exception is passed as
context. The ``context`` as found by the router when the view was denied (which
you normally would expect) is available as ``request.context``.  The
``request`` is the  current :term:`request` representing the denied action.
Here's some sample code that implements a minimal forbidden view:
@@ -203,15 +200,15 @@
.. note::
   When a forbidden view callable is invoked, it is passed a
   :term:`request`.  The ``exception`` attribute of the request will be an
   instance of the :exc:`~pyramid.httpexceptions.HTTPForbidden` exception
   that caused the forbidden view to be called.  The value of
   ``request.exception.message`` will be a value explaining why the forbidden
   was raised and ``request.exception.result`` will be extended information
   about the forbidden exception.  These messages have different values
   depending whether the ``pyramid.debug_authorization`` environment setting
   is true or false.
   When a forbidden view callable is invoked, it is passed a :term:`request`.
   The ``exception`` attribute of the request will be an instance of the
   :exc:`~pyramid.httpexceptions.HTTPForbidden` exception that caused the
   forbidden view to be called.  The value of ``request.exception.message``
   will be a value explaining why the forbidden exception was raised, and
   ``request.exception.result`` will be extended information about the
   forbidden exception.  These messages have different values depending on
   whether the ``pyramid.debug_authorization`` environment setting is true or
   false.
.. index::
   single: request factory
@@ -223,11 +220,11 @@
Whenever :app:`Pyramid` handles a request from a :term:`WSGI` server, it
creates a :term:`request` object based on the WSGI environment it has been
passed.  By default, an instance of the :class:`pyramid.request.Request`
class is created to represent the request object.
passed.  By default, an instance of the :class:`pyramid.request.Request` class
is created to represent the request object.
The class (aka "factory") that :app:`Pyramid` uses to create a request object
instance can be changed by passing a ``request_factory`` argument to the
The class (a.k.a., "factory") that :app:`Pyramid` uses to create a request
object instance can be changed by passing a ``request_factory`` argument to the
constructor of the :term:`configurator`.  This argument can be either a
callable or a :term:`dotted Python name` representing a callable.
@@ -242,7 +239,7 @@
   config = Configurator(request_factory=MyRequest)
If you're doing imperative configuration, and you'd rather do it after you've
already constructed a :term:`configurator` it can also be registered via the
already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_request_factory` method:
.. code-block:: python
@@ -262,19 +259,19 @@
.. _adding_request_method:
Adding Methods or Properties to Request Object
----------------------------------------------
Adding Methods or Properties to a Request Object
------------------------------------------------
.. versionadded:: 1.4.
Since each Pyramid application can only have one :term:`request` factory,
:ref:`changing the request factory <changing_the_request_factory>`
is not that extensible, especially if you want to build composable features
(e.g., Pyramid add-ons and plugins).
:ref:`changing the request factory <changing_the_request_factory>` is not that
extensible, especially if you want to build composable features (e.g., Pyramid
add-ons and plugins).
A lazy property can be registered to the request object via the
:meth:`pyramid.config.Configurator.add_request_method` API. This allows you
to specify a callable that will be available on the request object, but will not
:meth:`pyramid.config.Configurator.add_request_method` API. This allows you to
specify a callable that will be available on the request object, but will not
actually execute the function until accessed.
.. warning::
@@ -298,9 +295,10 @@
   config.add_request_method(total)
   config.add_request_method(prop, reify=True)
In the above example, ``total`` is added as a method. However, ``prop`` is added
as a property and its result is cached per-request by setting ``reify=True``.
This way, we eliminate the overhead of running the function multiple times.
In the above example, ``total`` is added as a method. However, ``prop`` is
added as a property and its result is cached per-request by setting
``reify=True``. This way, we eliminate the overhead of running the function
multiple times.
   >>> request.total(1, 2, 3)
   6
@@ -354,18 +352,18 @@
.. _changing_the_response_factory:
Changing the Response Factory
-------------------------------
-----------------------------
.. versionadded:: 1.6
Whenever :app:`Pyramid` returns a response from a view it creates a
Whenever :app:`Pyramid` returns a response from a view, it creates a
:term:`response` object.  By default, an instance of the
:class:`pyramid.response.Response` class is created to represent the response
object.
The factory that :app:`Pyramid` uses to create a response object instance can be
changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to
the constructor of the :term:`configurator`.  This argument can be either a
The factory that :app:`Pyramid` uses to create a response object instance can
be changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument
to the constructor of the :term:`configurator`.  This argument can be either a
callable or a :term:`dotted Python name` representing a callable.
The factory takes a single positional argument, which is a :term:`Request`
@@ -381,8 +379,8 @@
   config = Configurator(response_factory=lambda r: MyResponse())
If you're doing imperative configuration, and you'd rather do it after you've
already constructed a :term:`configurator` it can also be registered via the
If you're doing imperative configuration and you'd rather do it after you've
already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_response_factory` method:
.. code-block:: python
@@ -403,13 +401,13 @@
.. _beforerender_event:
Using The Before Render Event
Using the Before Render Event
-----------------------------
Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect
and modify the set of :term:`renderer globals` before they are passed to a
:term:`renderer`.  This event object iself has a dictionary-like interface
that can be used for this purpose.  For example:
:term:`renderer`.  This event object iself has a dictionary-like interface that
can be used for this purpose.  For example:
.. code-block:: python
    :linenos:
@@ -421,22 +419,22 @@
    def add_global(event):
        event['mykey'] = 'foo'
An object of this type is sent as an event just before a :term:`renderer`
is invoked.
An object of this type is sent as an event just before a :term:`renderer` is
invoked.
If a subscriber attempts to add a key that already exist in the renderer
If a subscriber attempts to add a key that already exists in the renderer
globals dictionary, a :exc:`KeyError` is raised.  This limitation is enforced
because event subscribers do not possess any relative ordering.  The set of
keys added to the renderer globals dictionary by all
:class:`pyramid.events.BeforeRender` subscribers and renderer globals
factories must be unique.
:class:`pyramid.events.BeforeRender` subscribers and renderer globals factories
must be unique.
The dictionary returned from the view is accessible through the
:attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender`
event.
Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from
your view callable, like so:
Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from your
view callable, like so:
.. code-block:: python
   :linenos:
@@ -492,24 +490,23 @@
           response.cache_control.max_age = 360
   request.add_response_callback(cache_callback)
No response callback is called if an unhandled exception happens in
application code, or if the response object returned by a :term:`view
callable` is invalid.  Response callbacks *are*, however, invoked when a
:term:`exception view` is rendered successfully: in such a case, the
:attr:`request.exception` attribute of the request when it enters a response
callback will be an exception object instead of its default value of
``None``.
No response callback is called if an unhandled exception happens in application
code, or if the response object returned by a :term:`view callable` is invalid.
Response callbacks *are*, however, invoked when a :term:`exception view` is
rendered successfully.  In such a case, the :attr:`request.exception` attribute
of the request when it enters a response callback will be an exception object
instead of its default value of ``None``.
Response callbacks are called in the order they're added
(first-to-most-recently-added).  All response callbacks are called *before*
the :class:`~pyramid.events.NewResponse` event is sent.  Errors raised by
response callbacks are not handled specially.  They will be propagated to the
caller of the :app:`Pyramid` router application.
(first-to-most-recently-added).  All response callbacks are called *before* the
:class:`~pyramid.events.NewResponse` event is sent.  Errors raised by response
callbacks are not handled specially.  They will be propagated to the caller of
the :app:`Pyramid` router application.
A response callback has a lifetime of a *single* request.  If you want a
response callback to happen as the result of *every* request, you must
re-register the callback into every new request (perhaps within a subscriber
of a :class:`~pyramid.events.NewRequest` event).
re-register the callback into every new request (perhaps within a subscriber of
a :class:`~pyramid.events.NewRequest` event).
.. index::
   single: finished callback
@@ -520,15 +517,15 @@
------------------------
A :term:`finished callback` is a function that will be called unconditionally
by the :app:`Pyramid` :term:`router` at the very end of request processing.
A finished callback can be used to perform an action at the end of a request
by the :app:`Pyramid` :term:`router` at the very end of request processing. A
finished callback can be used to perform an action at the end of a request
unconditionally.
The :meth:`pyramid.request.Request.add_finished_callback` method is used to
register a finished callback.
A finished callback is a callable which accepts a single positional
parameter: ``request``.  For example:
A finished callback is a callable which accepts a single positional parameter:
``request``.  For example:
.. code-block:: python
   :linenos:
@@ -543,29 +540,27 @@
   request.add_finished_callback(log_callback)
Finished callbacks are called in the order they're added
(first-to-most-recently-added).  Finished callbacks (unlike a
:term:`response callback`) are *always* called, even if an exception
happens in application code that prevents a response from being
generated.
(first-to-most-recently-added).  Finished callbacks (unlike a :term:`response
callback`) are *always* called, even if an exception happens in application
code that prevents a response from being generated.
The set of finished callbacks associated with a request are called *very
late* in the processing of that request; they are essentially the very last
thing called by the :term:`router` before a request "ends". They are called
after response processing has already occurred in a top-level ``finally:``
block within the router request processing code.  As a result, mutations
performed to the ``request`` provided to a finished callback will have no
meaningful effect, because response processing will have already occurred,
and the request's scope will expire almost immediately after all finished
callbacks have been processed.
The set of finished callbacks associated with a request are called *very late*
in the processing of that request; they are essentially the very last thing
called by the :term:`router` before a request "ends". They are called after
response processing has already occurred in a top-level ``finally:`` block
within the router request processing code.  As a result, mutations performed to
the ``request`` provided to a finished callback will have no meaningful effect,
because response processing will have already occurred, and the request's scope
will expire almost immediately after all finished callbacks have been
processed.
Errors raised by finished callbacks are not handled specially.  They
will be propagated to the caller of the :app:`Pyramid` router
application.
Errors raised by finished callbacks are not handled specially.  They will be
propagated to the caller of the :app:`Pyramid` router application.
A finished callback has a lifetime of a *single* request.  If you want a
finished callback to happen as the result of *every* request, you must
re-register the callback into every new request (perhaps within a subscriber
of a :class:`~pyramid.events.NewRequest` event).
re-register the callback into every new request (perhaps within a subscriber of
a :class:`~pyramid.events.NewRequest` event).
.. index::
   single: traverser
@@ -577,8 +572,8 @@
The default :term:`traversal` algorithm that :app:`Pyramid` uses is explained
in :ref:`traversal_algorithm`.  Though it is rarely necessary, this default
algorithm can be swapped out selectively for a different traversal pattern
via configuration.
algorithm can be swapped out selectively for a different traversal pattern via
configuration.
.. code-block:: python
   :linenos:
@@ -624,10 +619,10 @@
More than one traversal algorithm can be active at the same time.  For
instance, if your :term:`root factory` returns more than one type of object
conditionally, you could claim that an alternate traverser adapter is "for"
conditionally, you could claim that an alternative traverser adapter is "for"
only one particular class or interface.  When the root factory returned an
object that implemented that class or interface, a custom traverser would be
used.  Otherwise, the default traverser would be used.  For example:
used.  Otherwise the default traverser would be used.  For example:
.. code-block:: python
   :linenos:
@@ -639,13 +634,13 @@
   config.add_traverser(Traverser, MyRoot)
If the above stanza was added to a Pyramid ``__init__.py`` file's ``main``
function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only
when the application :term:`root factory` returned an instance of the
function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only when
the application :term:`root factory` returned an instance of the
``myapp.resources.MyRoot`` object.  Otherwise it would use the default
:app:`Pyramid` traverser to do traversal.
.. index::
   single: url generator
   single: URL generator
.. _changing_resource_url:
@@ -655,9 +650,8 @@
When you add a traverser as described in :ref:`changing_the_traverser`, it's
often convenient to continue to use the
:meth:`pyramid.request.Request.resource_url` API.  However, since the way
traversal is done will have been modified, the URLs it generates by default
may be incorrect when used against resources derived from your custom
traverser.
traversal is done will have been modified, the URLs it generates by default may
be incorrect when used against resources derived from your custom traverser.
If you've added a traverser, you can change how
:meth:`~pyramid.request.Request.resource_url` generates a URL for a specific
@@ -674,13 +668,13 @@
   config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)
In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will
be used to provide services to :meth:`~pyramid.request.Request.resource_url`
any time the :term:`resource` passed to ``resource_url`` is of the class
In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be
used to provide services to :meth:`~pyramid.request.Request.resource_url` any
time the :term:`resource` passed to ``resource_url`` is of the class
``myapp.resources.MyRoot``.  The ``resource_iface`` argument ``MyRoot``
represents the type of interface that must be possessed by the resource for
this resource url factory to be found.  If the ``resource_iface`` argument is
omitted, this resource url adapter will be used for *all* resources.
omitted, this resource URL adapter will be used for *all* resources.
The API that must be implemented by a class that provides
:class:`~pyramid.interfaces.IResourceURL` is as follows:
@@ -693,8 +687,8 @@
          resource
      """
      def __init__(self, resource, request):
          """ Accept the resource and request and set self.physical_path and
          self.virtual_path"""
          """ Accept the resource and request and set self.physical_path and
          self.virtual_path """
          self.virtual_path =  some_function_of(resource, request)
          self.physical_path =  some_other_function_of(resource, request)
@@ -703,7 +697,8 @@
<https://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of the
:term:`Pylons` GitHub Pyramid repository.
See :meth:`pyramid.config.add_resource_url_adapter` for more information.
See :meth:`pyramid.config.Configurator.add_resource_url_adapter` for more
information.
.. index::
   single: IResponse
@@ -721,25 +716,24 @@
:meth:`pyramid.config.Configurator.add_response_adapter` or the
:class:`~pyramid.response.response_adapter` decorator.
Pyramid, in various places, adapts the result of calling a view callable to
the :class:`~pyramid.interfaces.IResponse` interface to ensure that the
object returned by the view callable is a "true" response object.  The vast
majority of time, the result of this adaptation is the result object itself,
as view callables written by "civilians" who read the narrative documentation
contained in this manual will always return something that implements the
:class:`~pyramid.interfaces.IResponse` interface.  Most typically, this will
be an instance of the :class:`pyramid.response.Response` class or a subclass.
If a civilian returns a non-Response object from a view callable that isn't
configured to use a :term:`renderer`, he will typically expect the router to
Pyramid, in various places, adapts the result of calling a view callable to the
:class:`~pyramid.interfaces.IResponse` interface to ensure that the object
returned by the view callable is a "true" response object.  The vast majority
of time, the result of this adaptation is the result object itself, as view
callables written by "civilians" who read the narrative documentation contained
in this manual will always return something that implements the
:class:`~pyramid.interfaces.IResponse` interface.  Most typically, this will be
an instance of the :class:`pyramid.response.Response` class or a subclass. If a
civilian returns a non-Response object from a view callable that isn't
configured to use a :term:`renderer`, they will typically expect the router to
raise an error.  However, you can hook Pyramid in such a way that users can
return arbitrary values from a view callable by providing an adapter which
converts the arbitrary return value into something that implements
:class:`~pyramid.interfaces.IResponse`.
For example, if you'd like to allow view callables to return bare string
objects (without requiring a :term:`renderer` to convert a string to a
response object), you can register an adapter which converts the string to a
Response:
objects (without requiring a :term:`renderer` to convert a string to a response
object), you can register an adapter which converts the string to a Response:
.. code-block:: python
   :linenos:
@@ -754,9 +748,9 @@
   config.add_response_adapter(string_response_adapter, str)
Likewise, if you want to be able to return a simplified kind of response
object from view callables, you can use the IResponse hook to register an
adapter to the more complex IResponse interface:
Likewise, if you want to be able to return a simplified kind of response object
from view callables, you can use the IResponse hook to register an adapter to
the more complex IResponse interface:
.. code-block:: python
   :linenos:
@@ -777,7 +771,7 @@
If you want to implement your own Response object instead of using the
:class:`pyramid.response.Response` object in any capacity at all, you'll have
to make sure the object implements every attribute and method outlined in
to make sure that the object implements every attribute and method outlined in
:class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses
``zope.interface.implementer(IResponse)`` as a class decorator.
@@ -789,7 +783,7 @@
   @implementer(IResponse)
   class MyResponse(object):
       # ... an implementation of every method and attribute
       # ... an implementation of every method and attribute
       # documented in IResponse should follow ...
When an alternate response object implementation is returned by a view
@@ -804,8 +798,8 @@
subclasses of the class) will natively provide IResponse.  The adapter
registered for ``webob.Response`` simply returns the response object.
Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`,
you can use the :class:`pyramid.response.response_adapter` decorator:
Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, you
can use the :class:`pyramid.response.response_adapter` decorator:
.. code-block:: python
   :linenos:
@@ -841,31 +835,29 @@
A view mapper is an object that accepts a set of keyword arguments and which
returns a callable.  The returned callable is called with the :term:`view
callable` object.  The returned callable should itself return another
callable which can be called with the "internal calling protocol" ``(context,
callable` object.  The returned callable should itself return another callable
which can be called with the "internal calling protocol" ``(context,
request)``.
You can use a view mapper in a number of ways:
- by setting a ``__view_mapper__`` attribute (which is the view mapper
  object) on the view callable itself
- by setting a ``__view_mapper__`` attribute (which is the view mapper object)
  on the view callable itself
- by passing the mapper object to
  :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator
  equivalents) as the ``mapper`` argument.
- by passing the mapper object to :meth:`pyramid.config.Configurator.add_view`
  (or its declarative and decorator equivalents) as the ``mapper`` argument
- by registering a *default* view mapper.
- by registering a *default* view mapper
Here's an example of a view mapper that emulates (somewhat) a Pylons
"controller".  The mapper is initialized with some keyword arguments.  Its
``__call__`` method accepts the view object (which will be a class).  It uses
the ``attr`` keyword argument it is passed to determine which attribute
should be used as an action method.  The wrapper method it returns accepts
``(context, request)`` and returns the result of calling the action method
with keyword arguments implied by the :term:`matchdict` after popping the
``action`` out of it.  This somewhat emulates the Pylons style of calling
action methods with routing parameters pulled out of the route matching dict
as keyword arguments.
the ``attr`` keyword argument it is passed to determine which attribute should
be used as an action method.  The wrapper method it returns accepts ``(context,
request)`` and returns the result of calling the action method with keyword
arguments implied by the :term:`matchdict` after popping the ``action`` out of
it.  This somewhat emulates the Pylons style of calling action methods with
routing parameters pulled out of the route matching dict as keyword arguments.
.. code-block:: python
   :linenos:
@@ -917,8 +909,8 @@
set a *default* view mapper (overriding the superdefault view mapper used by
Pyramid itself).
A *single* view registration can use a view mapper by passing the mapper as
the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
A *single* view registration can use a view mapper by passing the mapper as the
``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
.. index::
   single: configuration decorator
@@ -928,14 +920,14 @@
Registering Configuration Decorators
------------------------------------
Decorators such as :class:`~pyramid.view.view_config` don't change the
behavior of the functions or classes they're decorating.  Instead, when a
:term:`scan` is performed, a modified version of the function or class is
registered with :app:`Pyramid`.
Decorators such as :class:`~pyramid.view.view_config` don't change the behavior
of the functions or classes they're decorating.  Instead when a :term:`scan` is
performed, a modified version of the function or class is registered with
:app:`Pyramid`.
You may wish to have your own decorators that offer such behaviour. This is
possible by using the :term:`Venusian` package in the same way that it is
used by :app:`Pyramid`.
possible by using the :term:`Venusian` package in the same way that it is used
by :app:`Pyramid`.
By way of example, let's suppose you want to write a decorator that registers
the function it wraps with a :term:`Zope Component Architecture` "utility"
@@ -945,8 +937,7 @@
completed. A normal decorator would fail as it would be executed before the
configuration had even begun.
However, using :term:`Venusian`, the decorator could be written as
follows:
However, using :term:`Venusian`, the decorator could be written as follows:
.. code-block:: python
   :linenos:
@@ -968,18 +959,17 @@
           venusian.attach(wrapped, self.register)
           return wrapped
This decorator could then be used to register functions throughout
your code:
This decorator could then be used to register functions throughout your code:
.. code-block:: python
   :linenos:
   @registerFunction('/some/path')
   def my_function():
      do_stuff()
       do_stuff()
However, the utility would only be looked up when a :term:`scan` was
performed, enabling you to set up the utility in advance:
However, the utility would only be looked up when a :term:`scan` was performed,
enabling you to set up the utility in advance:
.. code-block:: python
   :linenos:
@@ -994,10 +984,10 @@
   class UtilityImplementation:
       def __init__(self):
          self.registrations = {}
           self.registrations = {}
       def register(self, path, callable_):
          self.registrations[path] = callable_
           self.registrations[path] = callable_
   if __name__ == '__main__':
       config = Configurator()
@@ -1021,27 +1011,27 @@
A :term:`tween` (a contraction of the word "between") is a bit of code that
sits between the Pyramid router's main request handling function and the
upstream WSGI component that uses :app:`Pyramid` as its "app".  This is a
feature that may be used by Pyramid framework extensions, to provide, for
feature that may be used by Pyramid framework extensions to provide, for
example, Pyramid-specific view timing support bookkeeping code that examines
exceptions before they are returned to the upstream WSGI application.  Tweens
behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of
behave a bit like :term:`WSGI` :term:`middleware`, but they have the benefit of
running in a context in which they have access to the Pyramid :term:`request`,
:term:`response` and :term:`application registry` as well as the Pyramid
:term:`response`, and :term:`application registry`, as well as the Pyramid
rendering machinery.
Creating a Tween
~~~~~~~~~~~~~~~~
To create a tween, you must write a "tween factory".  A tween factory
must be a globally importable callable which accepts two arguments:
``handler`` and ``registry``.  ``handler`` will be either the main
Pyramid request handling function or another tween.  ``registry`` will be the
Pyramid :term:`application registry` represented by this Configurator.  A
tween factory must return the tween (a callable object) when it is called.
To create a tween, you must write a "tween factory".  A tween factory must be a
globally importable callable which accepts two arguments: ``handler`` and
``registry``.  ``handler`` will be either the main Pyramid request handling
function or another tween.  ``registry`` will be the Pyramid :term:`application
registry` represented by this Configurator.  A tween factory must return the
tween (a callable object) when it is called.
A tween is called with a single argument, ``request``, which is the
:term:`request` created by Pyramid's router when it receives a WSGI request.
A tween should return a :term:`response`, usually the one generated by the
:term:`request` created by Pyramid's router when it receives a WSGI request. A
tween should return a :term:`response`, usually the one generated by the
downstream Pyramid application.
You can write the tween factory as a simple closure-returning function:
@@ -1089,14 +1079,14 @@
            return response
You should avoid mutating any state on the tween instance. The tween is
invoked once per request and any shared mutable state needs to be carefully
handled to avoid any race conditions.
You should avoid mutating any state on the tween instance. The tween is invoked
once per request and any shared mutable state needs to be carefully handled to
avoid any race conditions.
The closure style performs slightly better and enables you to conditionally
omit the tween from the request processing pipeline (see the following timing
tween example), whereas the class style makes it easier to have shared mutable
state, and it allows subclassing.
state and allows subclassing.
Here's a complete example of a tween that logs the time spent processing each
request:
@@ -1131,13 +1121,12 @@
In the above example, the tween factory defines a ``timing_tween`` tween and
returns it if ``asbool(registry.settings.get('do_timing'))`` is true.  It
otherwise simply returns the handler it was given.  The ``registry.settings``
attribute is a handle to the deployment settings provided by the user
(usually in an ``.ini`` file).  In this case, if the user has defined a
``do_timing`` setting, and that setting is ``True``, the user has said she
wants to do timing, so the tween factory returns the timing tween; it
otherwise just returns the handler it has been provided, preventing any
timing.
otherwise simply returns the handler which it was given.  The
``registry.settings`` attribute is a handle to the deployment settings provided
by the user (usually in an ``.ini`` file).  In this case, if the user has
defined a ``do_timing`` setting and that setting is ``True``, the user has said
they want to do timing, so the tween factory returns the timing tween; it
otherwise just returns the handler it has been provided, preventing any timing.
The example timing tween simply records the start time, calls the downstream
handler, logs the number of seconds consumed by the downstream handler, and
@@ -1163,29 +1152,28 @@
Note that you must use a :term:`dotted Python name` as the first argument to
:meth:`pyramid.config.Configurator.add_tween`; this must point at a tween
factory.  You cannot pass the tween factory object itself to the method: it
must be :term:`dotted Python name` that points to a globally importable
object.  In the above example, we assume that a ``timing_tween_factory``
tween factory was defined in a module named ``myapp.tweens``, so the tween
factory is importable as ``myapp.tweens.timing_tween_factory``.
must be :term:`dotted Python name` that points to a globally importable object.
In the above example, we assume that a ``timing_tween_factory`` tween factory
was defined in a module named ``myapp.tweens``, so the tween factory is
importable as ``myapp.tweens.timing_tween_factory``.
When you use :meth:`pyramid.config.Configurator.add_tween`, you're
instructing the system to use your tween factory at startup time unless the
user has provided an explicit tween list in his configuration.  This is
what's meant by an "implicit" tween.  A user can always elect to supply an
explicit tween list, reordering or disincluding implicitly added tweens.  See
When you use :meth:`pyramid.config.Configurator.add_tween`, you're instructing
the system to use your tween factory at startup time unless the user has
provided an explicit tween list in their configuration.  This is what's meant
by an "implicit" tween.  A user can always elect to supply an explicit tween
list, reordering or disincluding implicitly added tweens.  See
:ref:`explicit_tween_ordering` for more information about explicit tween
ordering.
If more than one call to :meth:`pyramid.config.Configurator.add_tween` is
made within a single application configuration, the tweens will be chained
together at application startup time.  The *first* tween factory added via
``add_tween`` will be called with the Pyramid exception view tween factory as
its ``handler`` argument, then the tween factory added directly after that
one will be called with the result of the first tween factory as its
``handler`` argument, and so on, ad infinitum until all tween factories have
been called. The Pyramid router will use the outermost tween produced by this
chain (the tween generated by the very last tween factory added) as its
request handler function.  For example:
If more than one call to :meth:`pyramid.config.Configurator.add_tween` is made
within a single application configuration, the tweens will be chained together
at application startup time.  The *first* tween factory added via ``add_tween``
will be called with the Pyramid exception view tween factory as its ``handler``
argument, then the tween factory added directly after that one will be called
with the result of the first tween factory as its ``handler`` argument, and so
on, ad infinitum until all tween factories have been called. The Pyramid router
will use the outermost tween produced by this chain (the tween generated by the
very last tween factory added) as its request handler function.  For example:
.. code-block:: python
    :linenos:
@@ -1196,8 +1184,7 @@
    config.add_tween('myapp.tween_factory1')
    config.add_tween('myapp.tween_factory2')
The above example will generate an implicit tween chain that looks like
this::
The above example will generate an implicit tween chain that looks like this::
    INGRESS (implicit)
    myapp.tween_factory2
@@ -1211,37 +1198,36 @@
By default, as described above, the ordering of the chain is controlled
entirely by the relative ordering of calls to
:meth:`pyramid.config.Configurator.add_tween`.  However, the caller of
add_tween can provide an optional hint that can influence the implicit tween
chain ordering by supplying ``under`` or ``over`` (or both) arguments to
:meth:`~pyramid.config.Configurator.add_tween`.  These hints are only
used when an explicit tween ordering is not used. See
:ref:`explicit_tween_ordering` for a description of how to set an explicit
tween ordering.
``add_tween`` can provide an optional hint that can influence the implicit
tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to
:meth:`~pyramid.config.Configurator.add_tween`.  These hints are only used when
an explicit tween ordering is not used. See :ref:`explicit_tween_ordering` for
a description of how to set an explicit tween ordering.
Allowable values for ``under`` or ``over`` (or both) are:
- ``None`` (the default).
- ``None`` (the default),
- A :term:`dotted Python name` to a tween factory: a string representing the
  predicted dotted name of a tween factory added in a call to ``add_tween``
  in the same configuration session.
- a :term:`dotted Python name` to a tween factory: a string representing the
  predicted dotted name of a tween factory added in a call to ``add_tween`` in
  the same configuration session,
- One of the constants :attr:`pyramid.tweens.MAIN`,
  :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`.
- one of the constants :attr:`pyramid.tweens.MAIN`,
  :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`, or
- An iterable of any combination of the above. This allows the user to specify
- an iterable of any combination of the above. This allows the user to specify
  fallbacks if the desired tween is not included, as well as compatibility
  with multiple other tweens.
Effectively, ``over`` means "closer to the request ingress than" and
``under`` means "closer to the main Pyramid application than".
You can think of an onion with outer layers over the inner layers,
the application being under all the layers at the center.
Effectively, ``over`` means "closer to the request ingress than" and ``under``
means "closer to the main Pyramid application than". You can think of an onion
with outer layers over the inner layers, the application being under all the
layers at the center.
For example, the following call to
:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the
tween factory represented by ``myapp.tween_factory`` directly 'above' (in
``ptweens`` order) the main Pyramid request handler.
:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the tween
factory represented by ``myapp.tween_factory`` directly "above" (in ``ptweens``
order) the main Pyramid request handler.
.. code-block:: python
   :linenos:
@@ -1250,8 +1236,7 @@
   config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)
The above example will generate an implicit tween chain that looks like
this::
The above example will generate an implicit tween chain that looks like this::
    INGRESS (implicit)
    pyramid.tweens.excview_tween_factory (implicit)
@@ -1259,9 +1244,8 @@
    MAIN (implicit)
Likewise, calling the following call to
:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this
tween factory 'above' the main handler but 'below' a separately added tween
factory:
:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this tween
factory "above" the main handler but "below" a separately added tween factory:
.. code-block:: python
   :linenos:
@@ -1274,8 +1258,7 @@
                    over=pyramid.tweens.MAIN,
                    under='myapp.tween_factory1')
The above example will generate an implicit tween chain that looks like
this::
The above example will generate an implicit tween chain that looks like this::
    INGRESS (implicit)
    pyramid.tweens.excview_tween_factory (implicit)
@@ -1288,28 +1271,28 @@
If all options for ``under`` (or ``over``) cannot be found in the current
configuration, it is an error. If some options are specified purely for
compatibilty with other tweens, just add a fallback of MAIN or INGRESS.
For example, ``under=('someothertween', 'someothertween2', INGRESS)``.
This constraint will require the tween to be located under both the
'someothertween' tween, the 'someothertween2' tween, and INGRESS. If any of
these is not in the current configuration, this constraint will only organize
itself based on the tweens that are present.
compatibilty with other tweens, just add a fallback of ``MAIN`` or ``INGRESS``.
For example, ``under=('someothertween', 'someothertween2', INGRESS)``. This
constraint will require the tween to be located under the ``someothertween``
tween, the ``someothertween2`` tween, and ``INGRESS``. If any of these is not
in the current configuration, this constraint will only organize itself based
on the tweens that are present.
.. _explicit_tween_ordering:
Explicit Tween Ordering
~~~~~~~~~~~~~~~~~~~~~~~
Implicit tween ordering is obviously only best-effort.  Pyramid will attempt
to provide an implicit order of tweens as best it can using hints provided by
calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's
only best-effort, if very precise tween ordering is required, the only
surefire way to get it is to use an explicit tween order.  The deploying user
can override the implicit tween inclusion and ordering implied by calls to
Implicit tween ordering is obviously only best-effort.  Pyramid will attempt to
provide an implicit order of tweens as best it can using hints provided by
calls to :meth:`~pyramid.config.Configurator.add_tween`.  But because it's only
best-effort, if very precise tween ordering is required, the only surefire way
to get it is to use an explicit tween order.  The deploying user can override
the implicit tween inclusion and ordering implied by calls to
:meth:`~pyramid.config.Configurator.add_tween` entirely by using the
``pyramid.tweens`` settings value.  When used, this settings value must be a
list of Python dotted names which will override the ordering (and inclusion)
of tween factories in the implicit tween chain.  For example:
list of Python dotted names which will override the ordering (and inclusion) of
tween factories in the implicit tween chain.  For example:
.. code-block:: ini
   :linenos:
@@ -1327,19 +1310,19 @@
In the above configuration, calls made during configuration to
:meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is
telling the system to use the tween factories he has listed in the
``pyramid.tweens`` configuration setting (each is a :term:`dotted Python
name` which points to a tween factory) instead of any tween factories added
via :meth:`pyramid.config.Configurator.add_tween`.  The *first* tween factory
in the ``pyramid.tweens`` list will be used as the producer of the effective
``pyramid.tweens`` configuration setting (each is a :term:`dotted Python name`
which points to a tween factory) instead of any tween factories added via
:meth:`pyramid.config.Configurator.add_tween`.  The *first* tween factory in
the ``pyramid.tweens`` list will be used as the producer of the effective
:app:`Pyramid` request handling function; it will wrap the tween factory
declared directly "below" it, ad infinitum.  The "main" Pyramid request
handler is implicit, and always "at the bottom".
declared directly "below" it, ad infinitum.  The "main" Pyramid request handler
is implicit, and always "at the bottom".
.. note::
   Pyramid's own :term:`exception view` handling logic is implemented
   as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`.
   If Pyramid exception view handling is desired, and tween factories are
   Pyramid's own :term:`exception view` handling logic is implemented as a
   tween factory function: :func:`pyramid.tweens.excview_tween_factory`.  If
   Pyramid exception view handling is desired, and tween factories are
   specified via the ``pyramid.tweens`` configuration setting, the
   :func:`pyramid.tweens.excview_tween_factory` function must be added to the
   ``pyramid.tweens`` configuration setting list explicitly.  If it is not
@@ -1348,30 +1331,30 @@
Tween Conflicts and Ordering Cycles
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid will prevent the same tween factory from being added to the tween
chain more than once using configuration conflict detection.  If you wish to
add the same tween factory more than once in a configuration, you should
either: a) use a tween factory that is a separate globally importable
instance object from the factory that it conflicts with b) use a function or
class as a tween factory with the same logic as the other tween factory it
conflicts with but with a different ``__name__`` attribute or c) call
Pyramid will prevent the same tween factory from being added to the tween chain
more than once using configuration conflict detection.  If you wish to add the
same tween factory more than once in a configuration, you should either: (a)
use a tween factory that is a separate globally importable instance object from
the factory that it conflicts with; (b) use a function or class as a tween
factory with the same logic as the other tween factory it conflicts with, but
with a different ``__name__`` attribute; or (c) call
:meth:`pyramid.config.Configurator.commit` between calls to
:meth:`pyramid.config.Configurator.add_tween`.
If a cycle is detected in implicit tween ordering when ``over`` and ``under``
are used in any call to "add_tween", an exception will be raised at startup
are used in any call to ``add_tween``, an exception will be raised at startup
time.
Displaying Tween Ordering
~~~~~~~~~~~~~~~~~~~~~~~~~
The ``ptweens`` command-line utility can be used to report the current
implict and explicit tween chains used by an application.  See
The ``ptweens`` command-line utility can be used to report the current implict
and explicit tween chains used by an application.  See
:ref:`displaying_tweens`.
.. _registering_thirdparty_predicates:
Adding A Third Party View, Route, or Subscriber Predicate
Adding a Third Party View, Route, or Subscriber Predicate
---------------------------------------------------------
.. versionadded:: 1.4
@@ -1381,10 +1364,10 @@
View and Route Predicates
~~~~~~~~~~~~~~~~~~~~~~~~~
View and route predicates used during configuration allow you to narrow the
set of circumstances under which a view or route will match.  For example,
the ``request_method`` view predicate can be used to ensure a view callable
is only invoked when the request's method is ``POST``:
View and route predicates used during configuration allow you to narrow the set
of circumstances under which a view or route will match.  For example, the
``request_method`` view predicate can be used to ensure a view callable is only
invoked when the request's method is ``POST``:
.. code-block:: python
@@ -1398,9 +1381,9 @@
    config.add_route('name', '/foo', request_method='POST')
Many other built-in predicates exists (``request_param``, and others).  You
can add third-party predicates to the list of available predicates by using
one of :meth:`pyramid.config.Configurator.add_view_predicate` or
Many other built-in predicates exists (``request_param``, and others).  You can
add third-party predicates to the list of available predicates by using one of
:meth:`pyramid.config.Configurator.add_view_predicate` or
:meth:`pyramid.config.Configurator.add_route_predicate`.  The former adds a
view predicate, the latter a route predicate.
@@ -1428,7 +1411,7 @@
The second argument is a view or route predicate factory, or a :term:`dotted
Python name` which refers to a view or route predicate factory.  A view or
route predicate factory is most often a class with a constructor
(``__init__``), a ``text`` method, a ``phash`` method and a ``__call__``
(``__init__``), a ``text`` method, a ``phash`` method, and a ``__call__``
method. For example:
.. code-block:: python
@@ -1448,27 +1431,27 @@
The constructor of a predicate factory takes two arguments: ``val`` and
``config``.  The ``val`` argument will be the argument passed to
``view_config`` (or ``add_view``).  In the example above, it will be the
string ``File``.  The second arg, ``config`` will be the Configurator
instance at the time of configuration.
``view_config`` (or ``add_view``).  In the example above, it will be the string
``File``.  The second argument, ``config``, will be the Configurator instance
at the time of configuration.
The ``text`` method must return a string.  It should be useful to describe
the behavior of the predicate in error messages.
The ``text`` method must return a string.  It should be useful to describe the
behavior of the predicate in error messages.
The ``phash`` method must return a string or a sequence of strings.  It's
most often the same as ``text``, as long as ``text`` uniquely describes the
predicate's name and the value passed to the constructor.  If ``text`` is
more general, or doesn't describe things that way, ``phash`` should return a
string with the name and the value serialized.  The result of ``phash`` is
not seen in output anywhere, it just informs the uniqueness constraints for
view configuration.
The ``phash`` method must return a string or a sequence of strings.  It's most
often the same as ``text``, as long as ``text`` uniquely describes the
predicate's name and the value passed to the constructor.  If ``text`` is more
general, or doesn't describe things that way, ``phash`` should return a string
with the name and the value serialized.  The result of ``phash`` is not seen in
output anywhere, it just informs the uniqueness constraints for view
configuration.
The ``__call__`` method of a predicate factory must accept a resource
(``context``) and a request, and must return ``True`` or ``False``.  It is
the "meat" of the predicate.
(``context``) and a request, and must return ``True`` or ``False``.  It is the
"meat" of the predicate.
You can use the same predicate factory as both a view predicate and as a
route predicate, but you'll need to call ``add_view_predicate`` and
You can use the same predicate factory as both a view predicate and as a route
predicate, but you'll need to call ``add_view_predicate`` and
``add_route_predicate`` separately with the same factory.
.. _subscriber_predicates:
@@ -1476,16 +1459,16 @@
Subscriber Predicates
~~~~~~~~~~~~~~~~~~~~~
Subscriber predicates work almost exactly like view and route predicates.
They narrow the set of circumstances in which a subscriber will be called.
There are several minor differences between a subscriber predicate and a
view/route predicate:
Subscriber predicates work almost exactly like view and route predicates. They
narrow the set of circumstances in which a subscriber will be called. There are
several minor differences between a subscriber predicate and a view or route
predicate:
- There are no default subscriber predicates.  You must register one to use
  one.
- The ``__call__`` method of a subscriber predicate accepts a single
  ``event`` object instead of a ``context`` and a ``request``.
- The ``__call__`` method of a subscriber predicate accepts a single ``event``
  object instead of a ``context`` and a ``request``.
- Not every subscriber predicate can be used with every event type.  Some
  subscriber predicates will assume a certain event type.
@@ -1519,8 +1502,8 @@
Once a subscriber predicate is registered, you can use it in a call to
:meth:`pyramid.config.Configurator.add_subscriber` or to
:class:`pyramid.events.subscriber`.  Here's an example of using the
previously registered ``request_path_startswith`` predicate in a call to
:class:`pyramid.events.subscriber`.  Here's an example of using the previously
registered ``request_path_startswith`` predicate in a call to
:meth:`~pyramid.config.Configurator.add_subscriber`:
.. code-block:: python
@@ -1533,7 +1516,7 @@
    # and at configuration time
    config.add_subscriber(yosubscriber, NewRequest,
    config.add_subscriber(yosubscriber, NewRequest,
           request_path_startswith='/add_yo')
Here's the same subscriber/predicate/event-type combination used via
@@ -1548,22 +1531,19 @@
    def yosubscriber(event):
        event.request.yo = 'YO!'
In either of the above configurations, the ``yosubscriber`` callable will
only be called if the request path starts with ``/add_yo``.  Otherwise the
event subscriber will not be called.
In either of the above configurations, the ``yosubscriber`` callable will only
be called if the request path starts with ``/add_yo``.  Otherwise the event
subscriber will not be called.
Note that the ``request_path_startswith`` subscriber you defined can be used
with events that have a ``request`` attribute, but not ones that do not.  So,
for example, the predicate can be used with subscribers registered for
:class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound`
events, but it cannot be used with subscribers registered for
:class:`pyramid.events.ApplicationCreated` because the latter type of event
has no ``request`` attribute.  The point being: unlike route and view
predicates, not every type of subscriber predicate will necessarily be
applicable for use in every subscriber registration.  It is not the
responsibility of the predicate author to make every predicate make sense for
every event type; it is the responsibility of the predicate consumer to use
predicates that make sense for a particular event type registration.
:class:`pyramid.events.ApplicationCreated` because the latter type of event has
no ``request`` attribute.  The point being, unlike route and view predicates,
not every type of subscriber predicate will necessarily be applicable for use
in every subscriber registration.  It is not the responsibility of the
predicate author to make every predicate make sense for every event type; it is
the responsibility of the predicate consumer to use predicates that make sense
for a particular event type registration.
docs/narr/hybrid.rst
@@ -12,28 +12,26 @@
.. warning::
   Reasoning about the behavior of a "hybrid" URL dispatch + traversal
   application can be challenging.  To successfully reason about using
   URL dispatch and traversal together, you need to understand URL
   pattern matching, root factories, and the :term:`traversal`
   algorithm, and the potential interactions between them.  Therefore,
   we don't recommend creating an application that relies on hybrid
   behavior unless you must.
   application can be challenging.  To successfully reason about using URL
   dispatch and traversal together, you need to understand URL pattern
   matching, root factories, and the :term:`traversal` algorithm, and the
   potential interactions between them.  Therefore, we don't recommend creating
   an application that relies on hybrid behavior unless you must.
A Review of Non-Hybrid Applications
-----------------------------------
When used according to the tutorials in its documentation
:app:`Pyramid` is a "dual-mode" framework: the tutorials explain
how to create an application in terms of using either :term:`url
dispatch` *or* :term:`traversal`.  This chapter details how you might
combine these two dispatch mechanisms, but we'll review how they work
in isolation before trying to combine them.
When used according to the tutorials in its documentation, :app:`Pyramid` is a
"dual-mode" framework: the tutorials explain how to create an application in
terms of using either :term:`URL dispatch` *or* :term:`traversal`.  This
chapter details how you might combine these two dispatch mechanisms, but we'll
review how they work in isolation before trying to combine them.
URL Dispatch Only
~~~~~~~~~~~~~~~~~
An application that uses :term:`url dispatch` exclusively to map URLs to code
will often have statements like this within application startup
An application that uses :term:`URL dispatch` exclusively to map URLs to code
will often have statements like this within its application startup
configuration:
.. code-block:: python
@@ -48,11 +46,11 @@
   config.add_view('myproject.views.bazbuz', route_name='bazbuz')
Each :term:`route` corresponds to one or more view callables.  Each view
callable is associated with a route by passing a ``route_name`` parameter
that matches its name during a call to
:meth:`~pyramid.config.Configurator.add_view`.  When a route is matched
during a request, :term:`view lookup` is used to match the request to its
associated view callable.  The presence of calls to
callable is associated with a route by passing a ``route_name`` parameter that
matches its name during a call to
:meth:`~pyramid.config.Configurator.add_view`.  When a route is matched during
a request, :term:`view lookup` is used to match the request to its associated
view callable.  The presence of calls to
:meth:`~pyramid.config.Configurator.add_route` signify that an application is
using URL dispatch.
@@ -72,12 +70,11 @@
When the above configuration is applied to an application, the
``mypackage.views.foobar`` view callable above will be called when the URL
``/foobar`` is visited.  Likewise, the view ``mypackage.views.bazbuz`` will
be called when the URL ``/bazbuz`` is visited.
``/foobar`` is visited.  Likewise, the view ``mypackage.views.bazbuz`` will be
called when the URL ``/bazbuz`` is visited.
Typically, an application that uses traversal exclusively won't perform any
calls to :meth:`pyramid.config.Configurator.add_route` in its startup
code.
calls to :meth:`pyramid.config.Configurator.add_route` in its startup code.
.. index::
   single: hybrid applications
@@ -85,149 +82,139 @@
Hybrid Applications
-------------------
Either traversal or url dispatch alone can be used to create a
:app:`Pyramid` application.  However, it is also possible to
combine the concepts of traversal and url dispatch when building an
application: the result is a hybrid application.  In a hybrid
application, traversal is performed *after* a particular route has
matched.
Either traversal or URL dispatch alone can be used to create a :app:`Pyramid`
application.  However, it is also possible to combine the concepts of traversal
and URL dispatch when building an application, the result of which is a hybrid
application.  In a hybrid application, traversal is performed *after* a
particular route has matched.
A hybrid application is a lot more like a "pure" traversal-based
application than it is like a "pure" URL-dispatch based application.
But unlike in a "pure" traversal-based application, in a hybrid
application, :term:`traversal` is performed during a request after a
route has already matched.  This means that the URL pattern that
represents the ``pattern`` argument of a route must match the
``PATH_INFO`` of a request, and after the route pattern has matched,
most of the "normal" rules of traversal with respect to :term:`resource
location` and :term:`view lookup` apply.
A hybrid application is a lot more like a "pure" traversal-based application
than it is like a "pure" URL-dispatch based application. But unlike in a "pure"
traversal-based application, in a hybrid application :term:`traversal` is
performed during a request after a route has already matched.  This means that
the URL pattern that represents the ``pattern`` argument of a route must match
the ``PATH_INFO`` of a request, and after the route pattern has matched, most
of the "normal" rules of traversal with respect to :term:`resource location`
and :term:`view lookup` apply.
There are only four real differences between a purely traversal-based
application and a hybrid application:
- In a purely traversal based application, no routes are defined; in a
  hybrid application, at least one route will be defined.
- In a purely traversal-based application, no routes are defined.  In a hybrid
  application, at least one route will be defined.
- In a purely traversal based application, the root object used is
  global, implied by the :term:`root factory` provided at startup
  time; in a hybrid application, the :term:`root` object at which
  traversal begins may be varied on a per-route basis.
- In a purely traversal-based application, the root object used is global,
  implied by the :term:`root factory` provided at startup time.  In a hybrid
  application, the :term:`root` object at which traversal begins may be varied
  on a per-route basis.
- In a purely traversal-based application, the ``PATH_INFO`` of the
  underlying :term:`WSGI` environment is used wholesale as a traversal
  path; in a hybrid application, the traversal path is not the entire
  ``PATH_INFO`` string, but a portion of the URL determined by a
  matching pattern in the matched route configuration's pattern.
- In a purely traversal-based application, the ``PATH_INFO`` of the underlying
  :term:`WSGI` environment is used wholesale as a traversal path.  In a hybrid
  application, the traversal path is not the entire ``PATH_INFO`` string, but a
  portion of the URL determined by a matching pattern in the matched route
  configuration's pattern.
- In a purely traversal based application, view configurations which
  do not mention a ``route_name`` argument are considered during
  :term:`view lookup`; in a hybrid application, when a route is
  matched, only view configurations which mention that route's name as
  a ``route_name`` are considered during :term:`view lookup`.
- In a purely traversal-based application, view configurations which do not
  mention a ``route_name`` argument are considered during :term:`view lookup`.
  In a hybrid application, when a route is matched, only view configurations
  which mention that route's name as a ``route_name`` are considered during
  :term:`view lookup`.
More generally, a hybrid application *is* a traversal-based
application except:
More generally, a hybrid application *is* a traversal-based application except:
- the traversal *root* is chosen based on the route configuration of
  the route that matched instead of from the ``root_factory`` supplied
  during application startup configuration.
- the traversal *root* is chosen based on the route configuration of the route
  that matched, instead of from the ``root_factory`` supplied during
  application startup configuration.
- the traversal *path* is chosen based on the route configuration of
  the route that matched rather than from the ``PATH_INFO`` of a
  request.
- the traversal *path* is chosen based on the route configuration of the route
  that matched, rather than from the ``PATH_INFO`` of a request.
- the set of views that may be chosen during :term:`view lookup` when
  a route matches are limited to those which specifically name a
  ``route_name`` in their configuration that is the same as the
  matched route's ``name``.
- the set of views that may be chosen during :term:`view lookup` when a route
  matches are limited to those which specifically name a ``route_name`` in
  their configuration that is the same as the matched route's ``name``.
To create a hybrid mode application, use a :term:`route configuration`
that implies a particular :term:`root factory` and which also includes
a ``pattern`` argument that contains a special dynamic part: either
``*traverse`` or ``*subpath``.
To create a hybrid mode application, use a :term:`route configuration` that
implies a particular :term:`root factory` and which also includes a ``pattern``
argument that contains a special dynamic part: either ``*traverse`` or
``*subpath``.
The Root Object for a Route Match
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A hybrid application implies that traversal is performed during a
request after a route has matched.  Traversal, by definition, must
always begin at a root object.  Therefore it's important to know
*which* root object will be traversed after a route has matched.
A hybrid application implies that traversal is performed during a request after
a route has matched.  Traversal, by definition, must always begin at a root
object.  Therefore it's important to know *which* root object will be traversed
after a route has matched.
Figuring out which :term:`root` object results from a particular route
match is straightforward.  When a route is matched:
Figuring out which :term:`root` object results from a particular route match is
straightforward.  When a route is matched:
- If the route's configuration has a ``factory`` argument which
  points to a :term:`root factory` callable, that callable will be
  called to generate a :term:`root` object.
- If the route's configuration has a ``factory`` argument which points to a
  :term:`root factory` callable, that callable will be called to generate a
  :term:`root` object.
- If the route's configuration does not have a ``factory``
  argument, the *global* :term:`root factory` will be called to
  generate a :term:`root` object.  The global root factory is the
  callable implied by the ``root_factory`` argument passed to the
  :class:`~pyramid.config.Configurator` at application
  startup time.
- If the route's configuration does not have a ``factory`` argument, the
  *global* :term:`root factory` will be called to generate a :term:`root`
  object.  The global root factory is the callable implied by the
  ``root_factory`` argument passed to the :class:`~pyramid.config.Configurator`
  at application startup time.
- If a ``root_factory`` argument is not provided to the
  :class:`~pyramid.config.Configurator` at startup time, a
  *default* root factory is used.  The default root factory is used to
  generate a root object.
  :class:`~pyramid.config.Configurator` at startup time, a *default* root
  factory is used.  The default root factory is used to generate a root object.
.. note::
   Root factories related to a route were explained previously within
   :ref:`route_factories`.  Both the global root factory and default
   root factory were explained previously within
   :ref:`the_resource_tree`.
   :ref:`route_factories`.  Both the global root factory and default root
   factory were explained previously within :ref:`the_resource_tree`.
.. index::
   pair: hybrid applications; *traverse route pattern
.. _using_traverse_in_a_route_pattern:
Using ``*traverse`` In a Route Pattern
Using ``*traverse`` in a Route Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A hybrid application most often implies the inclusion of a route
configuration that contains the special token ``*traverse`` at the end
of a route's pattern:
A hybrid application most often implies the inclusion of a route configuration
that contains the special token ``*traverse`` at the end of a route's pattern:
.. code-block:: python
   :linenos:
   config.add_route('home', '{foo}/{bar}/*traverse')
A ``*traverse`` token at the end of the pattern in a route's
configuration implies a "remainder" *capture* value.  When it is used,
it will match the remainder of the path segments of the URL.  This
remainder becomes the path used to perform traversal.
A ``*traverse`` token at the end of the pattern in a route's configuration
implies a "remainder" *capture* value.  When it is used, it will match the
remainder of the path segments of the URL.  This remainder becomes the path
used to perform traversal.
.. note::
   The ``*remainder`` route pattern syntax is explained in more
   detail within :ref:`route_pattern_syntax`.
   The ``*remainder`` route pattern syntax is explained in more detail within
   :ref:`route_pattern_syntax`.
A hybrid mode application relies more heavily on :term:`traversal` to do
:term:`resource location` and :term:`view lookup` than most examples indicate
within :ref:`urldispatch_chapter`.
Because the pattern of the above route ends with ``*traverse``, when this
route configuration is matched during a request, :app:`Pyramid` will attempt
to use :term:`traversal` against the :term:`root` object implied by the
:term:`root factory` that is implied by the route's configuration.  Since no
Because the pattern of the above route ends with ``*traverse``, when this route
configuration is matched during a request, :app:`Pyramid` will attempt to use
:term:`traversal` against the :term:`root` object implied by the :term:`root
factory` that is implied by the route's configuration.  Since no
``root_factory`` argument is explicitly specified for this route, this will
either be the *global* root factory for the application, or the *default*
root factory.  Once :term:`traversal` has found a :term:`context` resource,
either be the *global* root factory for the application, or the *default* root
factory.  Once :term:`traversal` has found a :term:`context` resource,
:term:`view lookup` will be invoked in almost exactly the same way it would
have been invoked in a "pure" traversal-based application.
Let's assume there is no *global* :term:`root factory` configured in
this application. The *default* :term:`root factory` cannot be traversed:
it has no useful ``__getitem__`` method.  So we'll need to associate
this route configuration with a custom root factory in order to
create a useful hybrid application.  To that end, let's imagine that
we've created a root factory that looks like so in a module named
``routes.py``:
Let's assume there is no *global* :term:`root factory` configured in this
application. The *default* :term:`root factory` cannot be traversed; it has no
useful ``__getitem__`` method.  So we'll need to associate this route
configuration with a custom root factory in order to create a useful hybrid
application.  To that end, let's imagine that we've created a root factory that
looks like so in a module named ``routes.py``:
.. code-block:: python
   :linenos:
@@ -246,7 +233,7 @@
   def root_factory(request):
       return root
Above, we've defined a (bogus) resource tree that can be traversed, and a
Above we've defined a (bogus) resource tree that can be traversed, and a
``root_factory`` function that can be used as part of a particular route
configuration statement:
@@ -256,8 +243,8 @@
   config.add_route('home', '{foo}/{bar}/*traverse',
                    factory='mypackage.routes.root_factory')
The ``factory`` above points at the function we've defined.  It will return
an instance of the ``Resource`` class as a root object whenever this route is
The ``factory`` above points at the function we've defined.  It will return an
instance of the ``Resource`` class as a root object whenever this route is
matched.  Instances of the ``Resource`` class can be used for tree traversal
because they have a ``__getitem__`` method that does something nominally
useful. Since traversal uses ``__getitem__`` to walk the resources of a
@@ -266,39 +253,37 @@
.. note::
  We could have also used our ``root_factory`` function as the
  ``root_factory`` argument of the
  :class:`~pyramid.config.Configurator` constructor, instead
  of associating it with a particular route inside the route's
  configuration.  Every hybrid route configuration that is matched but
  which does *not* name a ``factory`` attribute will use the use
  global ``root_factory`` function to generate a root object.
  We could have also used our ``root_factory`` function as the ``root_factory``
  argument of the :class:`~pyramid.config.Configurator` constructor, instead of
  associating it with a particular route inside the route's configuration.
  Every hybrid route configuration that is matched, but which does *not* name a
  ``factory`` attribute, will use the  global ``root_factory`` function to
  generate a root object.
When the route configuration named ``home`` above is matched during a
request, the matchdict generated will be based on its pattern:
When the route configuration named ``home`` above is matched during a request,
the matchdict generated will be based on its pattern:
``{foo}/{bar}/*traverse``.  The "capture value" implied by the ``*traverse``
element in the pattern will be used to traverse the resource tree in order to
find a context resource, starting from the root object returned from the root
factory.  In the above example, the :term:`root` object found will be the
instance named ``root`` in ``routes.py``.
If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse``,
is ``http://example.com/one/two/a/b/c``, the traversal path used
against the root object will be ``a/b/c``.  As a result,
:app:`Pyramid` will attempt to traverse through the edges ``'a'``,
``'b'``, and ``'c'``, beginning at the root object.
If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse`` is
``http://example.com/one/two/a/b/c``, the traversal path used against the root
object will be ``a/b/c``.  As a result, :app:`Pyramid` will attempt to traverse
through the edges ``'a'``, ``'b'``, and ``'c'``, beginning at the root object.
In our above example, this particular set of traversal steps will mean that
the :term:`context` resource of the view would be the ``Resource`` object
we've named ``'c'`` in our bogus resource tree and the :term:`view name`
resulting from traversal will be the empty string; if you need a refresher
about why this outcome is presumed, see :ref:`traversal_algorithm`.
In our above example, this particular set of traversal steps will mean that the
:term:`context` resource of the view would be the ``Resource`` object we've
named ``'c'`` in our bogus resource tree, and the :term:`view name` resulting
from traversal will be the empty string.  If you need a refresher about why
this outcome is presumed, see :ref:`traversal_algorithm`.
At this point, a suitable view callable will be found and invoked
using :term:`view lookup` as described in :ref:`view_configuration`,
but with a caveat: in order for view lookup to work, we need to define
a view configuration that will match when :term:`view lookup` is
invoked after a route matches:
At this point, a suitable view callable will be found and invoked using
:term:`view lookup` as described in :ref:`view_configuration`, but with a
caveat: in order for view lookup to work, we need to define a view
configuration that will match when :term:`view lookup` is invoked after a route
matches:
.. code-block:: python
   :linenos:
@@ -307,28 +292,28 @@
                    factory='mypackage.routes.root_factory')
   config.add_view('mypackage.views.myview', route_name='home')
Note that the above call to
:meth:`~pyramid.config.Configurator.add_view` includes a ``route_name``
argument.  View configurations that include a ``route_name`` argument are
meant to associate a particular view declaration with a route, using the
route's name, in order to indicate that the view should *only be invoked when
the route matches*.
Note that the above call to :meth:`~pyramid.config.Configurator.add_view`
includes a ``route_name`` argument.  View configurations that include a
``route_name`` argument are meant to associate a particular view declaration
with a route, using the route's name, in order to indicate that the view should
*only be invoked when the route matches*.
Calls to :meth:`~pyramid.config.Configurator.add_view` may pass a
``route_name`` attribute, which refers to the value of an existing route's
``name`` argument.  In the above example, the route name is ``home``,
referring to the name of the route defined above it.
``name`` argument.  In the above example, the route name is ``home``, referring
to the name of the route defined above it.
The above ``mypackage.views.myview`` view callable will be invoked when:
The above ``mypackage.views.myview`` view callable will be invoked when the
following conditions are met:
- the route named "home" is matched
- The route named "home" is matched.
- the :term:`view name` resulting from traversal is the empty string.
- The :term:`view name` resulting from traversal is the empty string.
- the :term:`context` resource is any object.
- The :term:`context` resource is any object.
It is also possible to declare alternate views that may be invoked
when a hybrid route is matched:
It is also possible to declare alternative views that may be invoked when a
hybrid route is matched:
.. code-block:: python
   :linenos:
@@ -340,37 +325,37 @@
                   name='another')
The ``add_view`` call for ``mypackage.views.another_view`` above names a
different view and, more importantly, a different :term:`view name`.  The
above ``mypackage.views.another_view`` view will be invoked when:
different view and, more importantly, a different :term:`view name`.  The above
``mypackage.views.another_view`` view will be invoked when the following
conditions are met:
- the route named "home" is matched
- The route named "home" is matched.
- the :term:`view name` resulting from traversal is ``another``.
- The :term:`view name` resulting from traversal is ``another``.
- the :term:`context` resource is any object.
- The :term:`context` resource is any object.
For instance, if the URL ``http://example.com/one/two/a/another`` is provided
to an application that uses the previously mentioned resource tree, the
``mypackage.views.another`` view callable will be called instead of the
``mypackage.views.myview`` view callable because the :term:`view name` will
be ``another`` instead of the empty string.
``mypackage.views.another_view`` view callable will be called instead of the
``mypackage.views.myview`` view callable because the :term:`view name` will be
``another`` instead of the empty string.
More complicated matching can be composed.  All arguments to *route*
configuration statements and *view* configuration statements are
supported in hybrid applications (such as :term:`predicate`
arguments).
configuration statements and *view* configuration statements are supported in
hybrid applications (such as :term:`predicate` arguments).
Using the ``traverse`` Argument In a Route Definition
Using the ``traverse`` Argument in a Route Definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Rather than using the ``*traverse`` remainder marker in a pattern, you
can use the ``traverse`` argument to the
:meth:`~pyramid.config.Configurator.add_route` method.
Rather than using the ``*traverse`` remainder marker in a pattern, you can use
the ``traverse`` argument to the :meth:`~pyramid.config.Configurator.add_route`
method.
When you use the ``*traverse`` remainder marker, the traversal path is
limited to being the remainder segments of a request URL when a route
matches.  However, when you use the ``traverse`` argument or
attribute, you have more control over how to compose a traversal path.
When you use the ``*traverse`` remainder marker, the traversal path is limited
to being the remainder segments of a request URL when a route matches.
However, when you use the ``traverse`` argument or attribute, you have more
control over how to compose a traversal path.
Here's a use of the ``traverse`` pattern in a call to
:meth:`~pyramid.config.Configurator.add_route`:
@@ -381,30 +366,27 @@
   config.add_route('abc', '/articles/{article}/edit',
                    traverse='/{article}')
The syntax of the ``traverse`` argument is the same as it is for
``pattern``.
The syntax of the ``traverse`` argument is the same as it is for ``pattern``.
If, as above, the ``pattern`` provided is ``/articles/{article}/edit``,
and the ``traverse`` argument provided is ``/{article}``, when a
request comes in that causes the route to match in such a way that the
``article`` match value is ``1`` (when the request URI is
``/articles/1/edit``), the traversal path will be generated as ``/1``.
This means that the root object's ``__getitem__`` will be called with
the name ``1`` during the traversal phase.  If the ``1`` object
exists, it will become the :term:`context` of the request.
The :ref:`traversal_chapter` chapter has more information about traversal.
If, as above, the ``pattern`` provided is ``/articles/{article}/edit``, and the
``traverse`` argument provided is ``/{article}``, when a request comes in that
causes the route to match in such a way that the ``article`` match value is
``1`` (when the request URI is ``/articles/1/edit``), the traversal path will
be generated as ``/1``. This means that the root object's ``__getitem__`` will
be called with the name ``1`` during the traversal phase.  If the ``1`` object
exists, it will become the :term:`context` of the request. The
:ref:`traversal_chapter` chapter has more information about traversal.
If the traversal path contains segment marker names which are not
present in the pattern argument, a runtime error will occur.  The
``traverse`` pattern should not contain segment markers that do not
exist in the ``path``.
If the traversal path contains segment marker names which are not present in
the pattern argument, a runtime error will occur.  The ``traverse`` pattern
should not contain segment markers that do not exist in the ``path``.
Note that the ``traverse`` argument is ignored when attached to a
route that has a ``*traverse`` remainder marker in its pattern.
Note that the ``traverse`` argument is ignored when attached to a route that
has a ``*traverse`` remainder marker in its pattern.
Traversal will begin at the root object implied by this route (either
the global root, or the object returned by the ``factory`` associated
with this route).
Traversal will begin at the root object implied by this route (either the
global root, or the object returned by the ``factory`` associated with this
route).
.. index::
   pair: hybrid applications; global views
@@ -412,14 +394,13 @@
Making Global Views Match
+++++++++++++++++++++++++
By default, only view configurations that mention a ``route_name``
will be found during view lookup when a route that has a ``*traverse``
in its pattern matches.  You can allow views without a ``route_name``
attribute to match a route by adding the ``use_global_views`` flag to
the route definition.  For example, the ``myproject.views.bazbuz``
view below will be found if the route named ``abc`` below is matched
and the ``PATH_INFO`` is ``/abc/bazbuz``, even though the view
configuration statement does not have the ``route_name="abc"``
By default, only view configurations that mention a ``route_name`` will be
found during view lookup when a route that has a ``*traverse`` in its pattern
matches.  You can allow views without a ``route_name`` attribute to match a
route by adding the ``use_global_views`` flag to the route definition.  For
example, the ``myproject.views.bazbuz`` view below will be found if the route
named ``abc`` below is matched and the ``PATH_INFO`` is ``/abc/bazbuz``, even
though the view configuration statement does not have the ``route_name="abc"``
attribute.
.. code-block:: python
@@ -445,10 +426,10 @@
from the request's subpath when its ``use_subpath`` argument is ``True``, so
it's useful to be able to influence this value.
When ``*subpath`` exists in a pattern, no path is actually traversed,
but the traversal algorithm will return a :term:`subpath` list implied
by the capture value of ``*subpath``.  You'll see this pattern most
commonly in route declarations that look like this:
When ``*subpath`` exists in a pattern, no path is actually traversed, but the
traversal algorithm will return a :term:`subpath` list implied by the capture
value of ``*subpath``.  You'll see this pattern most commonly in route
declarations that look like this:
.. code-block:: python
   :linenos:
@@ -460,98 +441,13 @@
   config.add_route('static', '/static/*subpath')
   config.add_view(www, route_name='static')
``mypackage.views.www`` is an instance of
:class:`pyramid.static.static_view`.  This effectively tells the static
helper to traverse everything in the subpath as a filename.
``mypackage.views.www`` is an instance of :class:`pyramid.static.static_view`.
This effectively tells the static helper to traverse everything in the subpath
as a filename.
.. index::
   pair: hybrid applications; corner cases
Corner Cases
------------
A number of corner case "gotchas" exist when using a hybrid
application.  We'll detail them here.
Registering a Default View for a Route That Has a ``view`` Attribute
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. warning:: As of :app:`Pyramid` 1.1 this section is slated to be removed in
   a later documentation release because the ability to add views
   directly to the :term:`route configuration` by passing a ``view`` argument
   to ``add_route`` has been deprecated.
It is an error to provide *both* a ``view`` argument to a :term:`route
configuration` *and* a :term:`view configuration` which names a
``route_name`` that has no ``name`` value or the empty ``name`` value.  For
example, this pair of declarations will generate a conflict error at startup
time.
.. code-block:: python
   :linenos:
   config.add_route('home', '{foo}/{bar}/*traverse',
                    view='myproject.views.home')
   config.add_view('myproject.views.another', route_name='home')
This is because the ``view`` argument to the
:meth:`~pyramid.config.Configurator.add_route` above is an *implicit*
default view when that route matches.  ``add_route`` calls don't *need* to
supply a view attribute.  For example, this ``add_route`` call:
.. code-block:: python
   :linenos:
   config.add_route('home', '{foo}/{bar}/*traverse',
                    view='myproject.views.home')
Can also be spelled like so:
.. code-block:: python
   :linenos:
   config.add_route('home', '{foo}/{bar}/*traverse')
   config.add_view('myproject.views.home', route_name='home')
The two spellings are logically equivalent.  In fact, the former is just a
syntactical shortcut for the latter.
Binding Extra Views Against a Route Configuration that Doesn't Have a ``*traverse`` Element In Its Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here's another corner case that just makes no sense:
.. code-block:: python
   :linenos:
   config.add_route('abc', '/abc', view='myproject.views.abc')
   config.add_view('myproject.views.bazbuz', name='bazbuz',
                   route_name='abc')
The above view declaration is useless, because it will never be matched when
the route it references has matched.  Only the view associated with the route
itself (``myproject.views.abc``) will ever be invoked when the route matches,
because the default view is always invoked when a route matches and when no
post-match traversal is performed.
To make the above view declaration useful, the special ``*traverse``
token must end the route's pattern.  For example:
.. code-block:: python
   :linenos:
   config.add_route('abc', '/abc/*traverse', view='myproject.views.abc')
   config.add_view('myproject.views.bazbuz', name='bazbuz',
                   route_name='abc')
With the above configuration, the ``myproject.views.bazbuz`` view will
be invoked when the request URI is ``/abc/bazbuz``, assuming there is
no object contained by the root object with the key ``bazbuz``. A
different request URI, such as ``/abc/foo/bar``, would invoke the
default ``myproject.views.abc`` view.
.. index::
   pair: hybrid urls; generating
   pair: hybrid URLs; generating
.. _generating_hybrid_urls:
@@ -560,16 +456,16 @@
.. versionadded:: 1.5
The :meth:`pyramid.request.Request.resource_url` method and the
:meth:`pyramid.request.Request.resource_path` method both accept optional
The :meth:`pyramid.request.Request.resource_url` method and the
:meth:`pyramid.request.Request.resource_path` method both accept optional
keyword arguments that make it easier to generate route-prefixed URLs that
contain paths to traversal resources:``route_name``, ``route_kw``, and
contain paths to traversal resources: ``route_name``, ``route_kw``, and
``route_remainder_name``.
Any route that has a pattern that contains a ``*remainder`` pattern (any
stararg remainder pattern, such as ``*traverse`` or ``*subpath`` or ``*fred``)
can be used as the target name for ``request.resource_url(..., route_name=)``
and ``request.resource_path(..., route_name=)``.
stararg remainder pattern, such as ``*traverse``, ``*subpath``, or ``*fred``)
can be used as the target name for ``request.resource_url(..., route_name=)``
and ``request.resource_path(..., route_name=)``.
For example, let's imagine you have a route defined in your Pyramid application
like so:
@@ -578,7 +474,7 @@
   config.add_route('mysection', '/mysection*traverse')
If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
use the following incantation, assuming that the variable ``a`` below points to
a resource that is a child of the root with a ``__name__`` of ``a``:
@@ -592,14 +488,14 @@
   request.resource_path(a, route_name='mysection')
The path is virtual host aware, so if the ``X-Vhm-Root`` environ variable is
present in the request, and it's set to ``/a``, the above call to
``request.resource_url`` would generate ``http://example.com/mysection/``
and the above call to ``request.resource_path`` would generate ``/mysection/``.
See :ref:`virtual_root_support` for more information.
The path is virtual host aware, so if the ``X-Vhm-Root`` environment variable
is present in the request, and it's set to ``/a``, the above call to
``request.resource_url`` would generate ``http://example.com/mysection/``, and
the above call to ``request.resource_path`` would generate ``/mysection/``. See
:ref:`virtual_root_support` for more information.
If the route you're trying to use needs simple dynamic part values to be filled
in to succesfully generate the URL, you can pass these as the ``route_kw``
in to succesfully generate the URL, you can pass these as the ``route_kw``
argument to ``resource_url`` and ``resource_path``.  For example, assuming that
the route definition is like so:
@@ -613,15 +509,15 @@
   request.resource_url(a, route_name='mysection', route_kw={'id':'1'})
If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will
be ignored.
If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will be
ignored.
By default this feature works by calling ``route_url`` under the hood,
and passing the value of the resource path to that function as ``traverse``.
If your route has a different ``*stararg`` remainder name (such as
``*subpath``), you can tell ``resource_url`` or ``resource_path`` to use that
instead of  ``traverse`` by passing ``route_remainder_name``.  For example,
if you have the following route:
By default this feature works by calling ``route_url`` under the hood, and
passing the value of the resource path to that function as ``traverse``. If
your route has a different ``*stararg`` remainder name (such as ``*subpath``),
you can tell ``resource_url`` or ``resource_path`` to use that instead of
``traverse`` by passing ``route_remainder_name``.  For example, if you have the
following route:
.. code-block:: python
@@ -631,10 +527,10 @@
.. code-block:: python
   request.resource_path(a, route_name='mysection',
   request.resource_path(a, route_name='mysection',
                         route_remainder_name='subpath')
If you pass ``route_remainder_name`` but do not pass ``route_name``,
If you pass ``route_remainder_name`` but do not pass ``route_name``,
``route_remainder_name`` will be ignored.
If you try to use ``resource_path`` or ``resource_url`` when the ``route_name``
@@ -642,12 +538,11 @@
will not be raised, but the generated URL will not contain any remainder
information either.
All other values that are normally passable to ``resource_path`` and
``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and
All other values that are normally passable to ``resource_path`` and
``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and
positional elements) work as you might expect in this configuration.
Note that this feature is incompatible with the ``__resource_url__`` feature
(see :ref:`overriding_resource_url_generation`) implemented on resource
objects.  Any  ``__resource_url__`` supplied by your resource will be ignored
when you pass ``route_name``.
docs/narr/introspector.rst
@@ -20,8 +20,7 @@
Using the Introspector
----------------------
Here's an example of using Pyramid's introspector from within a view
callable:
Here's an example of using Pyramid's introspector from within a view callable:
.. code-block:: python
    :linenos:
@@ -36,10 +35,10 @@
        route_intr = introspector.get('routes', route_name)
        return Response(str(route_intr['pattern']))
This view will return a response that contains the "pattern" argument
provided to the ``add_route`` method of the route which matched when the view
was called.  It uses the :meth:`pyramid.interfaces.IIntrospector.get` method
to return an introspectable in the category ``routes`` with a
This view will return a response that contains the "pattern" argument provided
to the ``add_route`` method of the route which matched when the view was
called.  It uses the :meth:`pyramid.interfaces.IIntrospector.get` method to
return an introspectable in the category ``routes`` with a
:term:`discriminator` equal to the matched route name.  It then uses the
returned introspectable to obtain a "pattern" value.
@@ -56,9 +55,9 @@
Introspectable Objects
----------------------
Introspectable objects are returned from query methods of an introspector.
Each introspectable object implements the attributes and methods
documented at :class:`pyramid.interfaces.IIntrospectable`.
Introspectable objects are returned from query methods of an introspector. Each
introspectable object implements the attributes and methods documented at
:class:`pyramid.interfaces.IIntrospectable`.
The important attributes shared by all introspectables are the following:
@@ -74,12 +73,12 @@
``discriminator``
  A hashable object representing the unique value of this introspectable
  within its category.
  A hashable object representing the unique value of this introspectable within
  its category.
``discriminator_hash``
  The integer hash of the discriminator (useful for using in HTML links).
  The integer hash of the discriminator (useful in HTML links).
``type_name``
@@ -90,8 +89,8 @@
``action_info``
  An object describing the directive call site which caused this
  introspectable to be registered; contains attributes described in
  An object describing the directive call site which caused this introspectable
  to be registered.  It contains attributes described in
  :class:`pyramid.interfaces.IActionInfo`.
Besides having the attributes described above, an introspectable is a
@@ -116,7 +115,7 @@
  Each introspectable in the ``subscribers`` category represents a call to
  :meth:`pyramid.config.Configurator.add_subscriber` (or the decorator
  equivalent); each will have the following data.
  equivalent).  Each will have the following data.
  ``subscriber``
@@ -137,7 +136,7 @@
  ``predicates``
    The predicate objects created as the result of passing predicate arguments
    to ``add_subscriber``
    to ``add_subscriber``.
  ``derived_predicates``
@@ -149,7 +148,7 @@
  Each introspectable in the ``response adapters`` category represents a call
  to :meth:`pyramid.config.Configurator.add_response_adapter` (or a decorator
  equivalent); each will have the following data.
  equivalent).  Each will have the following data.
  ``adapter``
@@ -158,15 +157,14 @@
  ``type``
    The resolved ``type_or_iface`` argument passed to
    ``add_response_adapter``.
    The resolved ``type_or_iface`` argument passed to ``add_response_adapter``.
``root factories``
  Each introspectable in the ``root factories`` category represents a call to
  :meth:`pyramid.config.Configurator.set_root_factory` (or the Configurator
  constructor equivalent) *or* a ``factory`` argument passed to
  :meth:`pyramid.config.Configurator.add_route`; each will have the following
  :meth:`pyramid.config.Configurator.add_route`.  Each will have the following
  data.
  ``factory``
@@ -184,7 +182,7 @@
  Only one introspectable will exist in the ``session factory`` category.  It
  represents a call to :meth:`pyramid.config.Configurator.set_session_factory`
  (or the Configurator constructor equivalent); it will have the following
  (or the Configurator constructor equivalent).  It will have the following
  data.
  ``factory``
@@ -196,7 +194,7 @@
  Only one introspectable will exist in the ``request factory`` category.  It
  represents a call to :meth:`pyramid.config.Configurator.set_request_factory`
  (or the Configurator constructor equivalent); it will have the following
  (or the Configurator constructor equivalent).  It will have the following
  data.
  ``factory``
@@ -206,10 +204,10 @@
``locale negotiator``
  Only one introspectable will exist in the ``locale negotiator`` category.
  It represents a call to
  Only one introspectable will exist in the ``locale negotiator`` category.  It
  represents a call to
  :meth:`pyramid.config.Configurator.set_locale_negotiator` (or the
  Configurator constructor equivalent); it will have the following data.
  Configurator constructor equivalent).  It will have the following data.
  ``negotiator``
@@ -218,9 +216,9 @@
``renderer factories``
  Each introspectable in the ``renderer factories`` category represents a
  call to :meth:`pyramid.config.Configurator.add_renderer` (or the
  Configurator constructor equivalent); each will have the following data.
  Each introspectable in the ``renderer factories`` category represents a call
  to :meth:`pyramid.config.Configurator.add_renderer` (or the Configurator
  constructor equivalent).  Each will have the following data.
  ``name``
@@ -229,13 +227,12 @@
  ``factory``
    The factory object (the resolved ``factory`` argument to
    ``add_renderer``).
    The factory object (the resolved ``factory`` argument to ``add_renderer``).
``routes``
  Each introspectable in the ``routes`` category represents a call to
  :meth:`pyramid.config.Configurator.add_route`; each will have the following
  :meth:`pyramid.config.Configurator.add_route`.  Each will have the following
  data.
  ``name``
@@ -310,7 +307,7 @@
  There will be one and only one introspectable in the ``authentication
  policy`` category.  It represents a call to the
  :meth:`pyramid.config.Configurator.set_authentication_policy` method (or
  its Configurator constructor equivalent); it will have the following data.
  its Configurator constructor equivalent).  It will have the following data.
  ``policy``
@@ -319,10 +316,10 @@
``authorization policy``
  There will be one and only one introspectable in the ``authorization
  policy`` category.  It represents a call to the
  There will be one and only one introspectable in the ``authorization policy``
  category.  It represents a call to the
  :meth:`pyramid.config.Configurator.set_authorization_policy` method (or its
  Configurator constructor equivalent); it will have the following data.
  Configurator constructor equivalent).  It will have the following data.
  ``policy``
@@ -334,7 +331,7 @@
  There will be one and only one introspectable in the ``default permission``
  category.  It represents a call to the
  :meth:`pyramid.config.Configurator.set_default_permission` method (or its
  Configurator constructor equivalent); it will have the following data.
  Configurator constructor equivalent).  It will have the following data.
  ``value``
@@ -343,7 +340,7 @@
``views``
  Each introspectable in the ``views`` category represents a call to
  :meth:`pyramid.config.Configurator.add_view`; each will have the following
  :meth:`pyramid.config.Configurator.add_view`.  Each will have the following
  data.
  ``name``
@@ -423,8 +420,8 @@
  Each introspectable in the ``permissions`` category represents a call to
  :meth:`pyramid.config.Configurator.add_view` that has an explicit
  ``permission`` argument to *or* a call to
  :meth:`pyramid.config.Configurator.set_default_permission`; each will have
  ``permission`` argument *or* a call to
  :meth:`pyramid.config.Configurator.set_default_permission`.  Each will have
  the following data.
  ``value``
@@ -435,7 +432,7 @@
  Each introspectable in the ``templates`` category represents a call to
  :meth:`pyramid.config.Configurator.add_view` that has a ``renderer``
  argument which points to a template; each will have the following data.
  argument which points to a template.  Each will have the following data.
  ``name``
@@ -447,15 +444,15 @@
  ``renderer``
    The :class:`pyramid.interfaces.IRendererInfo` object which represents
    this template's renderer.
    The :class:`pyramid.interfaces.IRendererInfo` object which represents this
    template's renderer.
``view mappers``
  Each introspectable in the ``view mappers`` category represents a call to
  :meth:`pyramid.config.Configurator.add_view` that has an explicit
  ``mapper`` argument to *or* a call to
  :meth:`pyramid.config.Configurator.set_view_mapper`; each will have
  :meth:`pyramid.config.Configurator.add_view` that has an explicit ``mapper``
  argument *or* a call to
  :meth:`pyramid.config.Configurator.set_view_mapper`.  Each will have
  the following data.
  ``mapper``
@@ -465,14 +462,13 @@
``asset overrides``
  Each introspectable in the ``asset overrides`` category represents a call
  to :meth:`pyramid.config.Configurator.override_asset`; each will have the
  Each introspectable in the ``asset overrides`` category represents a call to
  :meth:`pyramid.config.Configurator.override_asset`.  Each will have the
  following data.
  ``to_override``
    The ``to_override`` argument (an asset spec) passed to
    ``override_asset``.
    The ``to_override`` argument (an asset spec) passed to ``override_asset``.
  ``override_with``
@@ -481,10 +477,10 @@
``translation directories``
  Each introspectable in the ``translation directories`` category represents
  an individual element in a ``specs`` argument passed to
  :meth:`pyramid.config.Configurator.add_translation_dirs`; each will have
  the following data.
  Each introspectable in the ``translation directories`` category represents an
  individual element in a ``specs`` argument passed to
  :meth:`pyramid.config.Configurator.add_translation_dirs`.  Each will have the
  following data.
  ``directory``
@@ -497,13 +493,13 @@
``tweens``
  Each introspectable in the ``tweens`` category represents a call to
  :meth:`pyramid.config.Configurator.add_tween`; each will have the following
  :meth:`pyramid.config.Configurator.add_tween`.  Each will have the following
  data.
  ``name``
    The dotted name to the tween factory as a string (passed as
    the ``tween_factory`` argument to ``add_tween``).
    The dotted name to the tween factory as a string (passed as the
    ``tween_factory`` argument to ``add_tween``).
  ``factory``
@@ -524,7 +520,7 @@
``static views``
  Each introspectable in the ``static views`` category represents a call to
  :meth:`pyramid.config.Configurator.add_static_view`; each will have the
  :meth:`pyramid.config.Configurator.add_static_view`.  Each will have the
  following data.
  ``name``
@@ -539,13 +535,13 @@
``traversers``
  Each introspectable in the ``traversers`` category represents a call to
  :meth:`pyramid.config.Configurator.add_traverser`; each will have the
  :meth:`pyramid.config.Configurator.add_traverser`.  Each will have the
  following data.
  ``iface``
    The (resolved) interface or class object that represents the return value
    of a root factory that this traverser will be used for.
    of a root factory for which this traverser will be used.
  ``adapter``
@@ -554,7 +550,7 @@
``resource url adapters``
  Each introspectable in the ``resource url adapters`` category represents a
  call to :meth:`pyramid.config.Configurator.add_resource_url_adapter`; each
  call to :meth:`pyramid.config.Configurator.add_resource_url_adapter`.  Each
  will have the following data.
  ``adapter``
@@ -564,19 +560,20 @@
  ``resource_iface``
    The (resolved) interface or class object that represents the resource
    interface that this url adapter is registered for.
    interface for which this URL adapter is registered.
  ``request_iface``
    The (resolved) interface or class object that represents the request
    interface that this url adapter is registered for.
    interface for which this URL adapter is registered.
Introspection in the Toolbar
----------------------------
The Pyramid debug toolbar (part of the ``pyramid_debugtoolbar`` package)
provides a canned view of all registered introspectables and their
relationships.  It looks something like this:
relationships.  It is currently under the "Global" tab in the main navigation,
and it looks something like this:
.. image:: tb_introspector.png
docs/narr/muchadoabouttraversal.rst
@@ -4,44 +4,44 @@
Much Ado About Traversal
========================
(Or, why you should care about it)
(Or, why you should care about it.)
.. note::
   This chapter was adapted, with permission, from a blog post by `Rob
   Miller <http://blog.nonsequitarian.org/>`_, originally published at
   http://blog.nonsequitarian.org/2010/much-ado-about-traversal/ .
   This chapter was adapted, with permission, from a blog post by `Rob Miller
   <http://blog.nonsequitarian.org/>`_, originally published at
   http://blog.nonsequitarian.org/2010/much-ado-about-traversal/.
Traversal is an alternative to :term:`URL dispatch` which allows
:app:`Pyramid` applications to map URLs to code.
Traversal is an alternative to :term:`URL dispatch` which allows :app:`Pyramid`
applications to map URLs to code.
.. note::
   
   Ex-Zope users who are already familiar with traversal and view lookup
   conceptually may want to skip directly to the :ref:`traversal_chapter`
   chapter, which discusses technical details.  This chapter is mostly aimed
   at people who have previous :term:`Pylons` experience or experience in
   another framework which does not provide traversal, and need an
   introduction to the "why" of traversal.
   chapter, which discusses technical details.  This chapter is mostly aimed at
   people who have previous :term:`Pylons` experience or experience in another
   framework which does not provide traversal, and need an introduction to the
   "why" of traversal.
Some folks who have been using Pylons and its Routes-based URL matching for a
long time are being exposed for the first time, via :app:`Pyramid`, to new
ideas such as ":term:`traversal`" and ":term:`view lookup`" as a way to route
incoming HTTP requests to callable code.  Some of the same folks believe that
traversal is hard to understand.  Others question its usefulness; URL
matching has worked for them so far, why should they even consider dealing
with another approach, one which doesn't fit their brain and which doesn't
provide any immediately obvious value?
traversal is hard to understand.  Others question its usefulness; URL matching
has worked for them so far, so why should they even consider dealing with
another approach, one which doesn't fit their brain and which doesn't provide
any immediately obvious value?
You can be assured that if you don't want to understand traversal, you don't
have to.  You can happily build :app:`Pyramid` applications with only
:term:`URL dispatch`.  However, there are some straightforward, real-world
use cases that are much more easily served by a traversal-based approach than
by a pattern-matching mechanism.  Even if you haven't yet hit one of these
use cases yourself, understanding these new ideas is worth the effort for any
web developer so you know when you might want to use them.  :term:`Traversal`
is actually a straightforward metaphor easily comprehended by anyone who's
ever used a run-of-the-mill file system with folders and files.
:term:`URL dispatch`.  However, there are some straightforward, real-world use
cases that are much more easily served by a traversal-based approach than by a
pattern-matching mechanism.  Even if you haven't yet hit one of these use cases
yourself, understanding these new ideas is worth the effort for any web
developer so you know when you might want to use them.  :term:`Traversal` is
actually a straightforward metaphor easily comprehended by anyone who's ever
used a run-of-the-mill file system with folders and files.
.. index::
   single: URL dispatch
@@ -49,34 +49,33 @@
URL Dispatch
------------
Let's step back and consider the problem we're trying to solve.  An
HTTP request for a particular path has been routed to our web
application.  The requested path will possibly invoke a specific
:term:`view callable` function defined somewhere in our app.  We're
trying to determine *which* callable function, if any, should be
invoked for a given requested URL.
Let's step back and consider the problem we're trying to solve.  An HTTP
request for a particular path has been routed to our web application.  The
requested path will possibly invoke a specific :term:`view callable` function
defined somewhere in our app.  We're trying to determine *which* callable
function, if any, should be invoked for a given requested URL.
Many systems, including Pyramid, offer a simple solution.  They offer the
concept of "URL matching".  URL matching approaches this problem by parsing
the URL path and comparing the results to a set of registered "patterns",
defined by a set of regular expressions, or some other URL path templating
syntax.  Each pattern is mapped to a callable function somewhere; if the
request path matches a specific pattern, the associated function is called.
If the request path matches more than one pattern, some conflict resolution
scheme is used, usually a simple order precedence so that the first match
will take priority over any subsequent matches.  If a request path doesn't
match any of the defined patterns, a "404 Not Found" response is returned.
concept of "URL matching".  URL matching approaches this problem by parsing the
URL path and comparing the results to a set of registered "patterns", defined
by a set of regular expressions or some other URL path templating syntax.  Each
pattern is mapped to a callable function somewhere; if the request path matches
a specific pattern, the associated function is called. If the request path
matches more than one pattern, some conflict resolution scheme is used, usually
a simple order precedence so that the first match will take priority over any
subsequent matches.  If a request path doesn't match any of the defined
patterns, a "404 Not Found" response is returned.
In Pyramid, we offer an implementation of URL matching which we call
:term:`URL dispatch`.  Using :app:`Pyramid` syntax, we might have a match
pattern such as ``/{userid}/photos/{photoid}``, mapped to a ``photo_view()``
function defined somewhere in our code.  Then a request for a path such as
In Pyramid, we offer an implementation of URL matching which we call :term:`URL
dispatch`.  Using :app:`Pyramid` syntax, we might have a match pattern such as
``/{userid}/photos/{photoid}``, mapped to a ``photo_view()`` function defined
somewhere in our code.  Then a request for a path such as
``/joeschmoe/photos/photo1`` would be a match, and the ``photo_view()``
function would be invoked to handle the request.  Similarly,
``/{userid}/blog/{year}/{month}/{postid}`` might map to a
``blog_post_view()`` function, so ``/joeschmoe/blog/2010/12/urlmatching``
would trigger the function, which presumably would know how to find and
render the ``urlmatching`` blog post.
``/{userid}/blog/{year}/{month}/{postid}`` might map to a ``blog_post_view()``
function, so ``/joeschmoe/blog/2010/12/urlmatching`` would trigger the
function, which presumably would know how to find and render the
``urlmatching`` blog post.
Historical Refresher
--------------------
@@ -88,65 +87,64 @@
:app:`Pyramid`.  Instead, we had general purpose HTTP servers that primarily
served files off of a file system.  The "root" of a given site mapped to a
particular folder somewhere on the file system.  Each segment of the request
URL path represented a subdirectory.  The final path segment would be either
a directory or a file, and once the server found the right file it would
package it up in an HTTP response and send it back to the client.  So serving
up a request for ``/joeschmoe/photos/photo1`` literally meant that there was
a ``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which
in turn contained a ``photo1`` file.  If at any point along the way we find
that there is not a folder or file matching the requested path, we return a
404 response.
URL path represented a subdirectory.  The final path segment would be either a
directory or a file, and once the server found the right file it would package
it up in an HTTP response and send it back to the client.  So serving up a
request for ``/joeschmoe/photos/photo1`` literally meant that there was a
``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which in
turn contained a ``photo1`` file.  If at any point along the way we find that
there is not a folder or file matching the requested path, we return a 404
response.
As the web grew more dynamic, however, a little bit of extra complexity was
added.  Technologies such as CGI and HTTP server modules were developed.
Files were still looked up on the file system, but if the file ended with
(for example) ``.cgi`` or ``.php``, or if it lived in a special folder,
instead of simply sending the file to the client the server would read the
file, execute it using an interpreter of some sort, and then send the output
from this process to the client as the final result.  The server
configuration specified which files would trigger some dynamic code, with the
default case being to just serve the static file.
added.  Technologies such as CGI and HTTP server modules were developed. Files
were still looked up on the file system, but if the file ended with (for
example) ``.cgi`` or ``.php``, or if it lived in a special folder, instead of
simply sending the file to the client the server would read the file, execute
it using an interpreter of some sort, and then send the output from this
process to the client as the final result.  The server configuration specified
which files would trigger some dynamic code, with the default case being to
just serve the static file.
.. index::
   single: traversal
Traversal (aka Resource Location)
---------------------------------
Traversal (a.k.a., Resource Location)
-------------------------------------
Believe it or not, if you understand how serving files from a file system
works, you understand traversal.  And if you understand that a server might do
something different based on what type of file a given request specifies,
then you understand view lookup.
something different based on what type of file a given request specifies, then
you understand view lookup.
The major difference between file system lookup and traversal is that a file
system lookup steps through nested directories and files in a file system
tree, while traversal steps through nested dictionary-type objects in a
:term:`resource tree`.  Let's take a detailed look at one of our example
paths, so we can see what I mean:
system lookup steps through nested directories and files in a file system tree,
while traversal steps through nested dictionary-type objects in a
:term:`resource tree`.  Let's take a detailed look at one of our example paths,
so we can see what I mean.
The path ``/joeschmoe/photos/photo1``, has four segments: ``/``,
``joeschmoe``, ``photos`` and ``photo1``.  With file system lookup we might
have a root folder (``/``) containing a nested folder (``joeschmoe``), which
contains another nested folder (``photos``), which finally contains a JPG
file (``photo1``).  With traversal, we instead have a dictionary-like root
object.  Asking for the ``joeschmoe`` key gives us another dictionary-like
object.  Asking this in turn for the ``photos`` key gives us yet another
mapping object, which finally (hopefully) contains the resource that we're
looking for within its values, referenced by the ``photo1`` key.
The path ``/joeschmoe/photos/photo1``, has four segments: ``/``, ``joeschmoe``,
``photos`` and ``photo1``.  With file system lookup we might have a root folder
(``/``) containing a nested folder (``joeschmoe``), which contains another
nested folder (``photos``), which finally contains a JPG file (``photo1``).
With traversal, we instead have a dictionary-like root object.  Asking for the
``joeschmoe`` key gives us another dictionary-like object.  Asking in turn for
the ``photos`` key gives us yet another mapping object, which finally
(hopefully) contains the resource that we're looking for within its values,
referenced by the ``photo1`` key.
In pure Python terms, then, the traversal or "resource location"
portion of satisfying the ``/joeschmoe/photos/photo1`` request
will look something like this pseudocode::
In pure Python terms, then, the traversal or "resource location" portion of
satisfying the ``/joeschmoe/photos/photo1`` request will look something like
this pseudocode::
    get_root()['joeschmoe']['photos']['photo1']
``get_root()`` is some function that returns a root traversal
:term:`resource`.  If all of the specified keys exist, then the returned
object will be the resource that is being requested, analogous to the JPG
file that was retrieved in the file system example.  If a :exc:`KeyError` is
generated anywhere along the way, :app:`Pyramid` will return 404.  (This
isn't precisely true, as you'll see when we learn about view lookup below,
but the basic idea holds.)
``get_root()`` is some function that returns a root traversal :term:`resource`.
If all of the specified keys exist, then the returned object will be the
resource that is being requested, analogous to the JPG file that was retrieved
in the file system example.  If a :exc:`KeyError` is generated anywhere along
the way, :app:`Pyramid` will return 404.  (This isn't precisely true, as you'll
see when we learn about view lookup below, but the basic idea holds.)
.. index::
   single: resource
@@ -159,10 +157,10 @@
What *are* they?"
Since :app:`Pyramid` is not a highly opinionated framework, it makes no
restriction on how a :term:`resource` is implemented; a developer can
implement them as he wishes.  One common pattern used is to persist all of
the resources, including the root, in a database as a graph.  The root object
is a dictionary-like object.  Dictionary-like objects in Python supply a
restriction on how a :term:`resource` is implemented; a developer can implement
them as they wish.  One common pattern used is to persist all of the resources,
including the root, in a database as a graph.  The root object is a
dictionary-like object.  Dictionary-like objects in Python supply a
``__getitem__`` method which is called when key lookup is done.  Under the
hood, when ``adict`` is a dictionary-like object, Python translates
``adict['a']`` to ``adict.__getitem__('a')``.  Try doing this in a Python
@@ -175,25 +173,24 @@
>>> adict.__getitem__('a')
1
The dictionary-like root object stores the ids of all of its subresources as
keys, and provides a ``__getitem__`` implementation that fetches them.  So
``get_root()`` fetches the unique root object, while
``get_root()['joeschmoe']`` returns a different object, also stored in the
database, which in turn has its own subresources and ``__getitem__``
implementation, etc.  These resources might be persisted in a relational
implementation, and so on.  These resources might be persisted in a relational
database, one of the many "NoSQL" solutions that are becoming popular these
days, or anywhere else, it doesn't matter.  As long as the returned objects
provide the dictionary-like API (i.e. as long as they have an appropriately
implemented ``__getitem__`` method) then traversal will work.
days, or anywhere else; it doesn't matter.  As long as the returned objects
provide the dictionary-like API (i.e., as long as they have an appropriately
implemented ``__getitem__`` method), then traversal will work.
In fact, you don't need a "database" at all.  You could use plain
dictionaries, with your site's URL structure hard-coded directly in
the Python source.  Or you could trivially implement a set of objects
with ``__getitem__`` methods that search for files in specific
directories, and thus precisely recreate the traditional mechanism of
having the URL path mapped directly to a folder structure on the file
system.  Traversal is in fact a superset of file system lookup.
In fact, you don't need a "database" at all.  You could use plain dictionaries,
with your site's URL structure hard-coded directly in the Python source.  Or
you could trivially implement a set of objects with ``__getitem__`` methods
that search for files in specific directories, and thus precisely recreate the
traditional mechanism of having the URL path mapped directly to a folder
structure on the file system.  Traversal is in fact a superset of file system
lookup.
.. note:: See the chapter entitled :ref:`resources_chapter` for a more
   technical overview of resources.
@@ -208,34 +205,33 @@
process by which a specific resource is retrieved according to a specific URL
path.  But what is "view lookup"?
The need for view lookup is simple: there is more than one possible action
that you might want to take after finding a :term:`resource`.  With our photo
The need for view lookup is simple: there is more than one possible action that
you might want to take after finding a :term:`resource`.  With our photo
example, for instance, you might want to view the photo in a page, but you
might also want to provide a way for the user to edit the photo and any
associated metadata.  We'll call the former the ``view`` view, and the latter
will be the ``edit`` view.  (Original, I know.)  :app:`Pyramid` has a
centralized view :term:`application registry` where named views can be
associated with specific resource types.  So in our example, we'll assume
that we've registered ``view`` and ``edit`` views for photo objects, and that
we've specified the ``view`` view as the default, so that
associated with specific resource types.  So in our example, we'll assume that
we've registered ``view`` and ``edit`` views for photo objects, and that we've
specified the ``view`` view as the default, so that
``/joeschmoe/photos/photo1/view`` and ``/joeschmoe/photos/photo1`` are
equivalent.  The edit view would sensibly be provided by a request for
``/joeschmoe/photos/photo1/edit``.
Hopefully it's clear that the first portion of the edit view's URL path is
going to resolve to the same resource as the non-edit version, specifically
the resource returned by ``get_root()['joeschmoe']['photos']['photo1']``.
But traveral ends there; the ``photo1`` resource doesn't have an ``edit``
key.  In fact, it might not even be a dictionary-like object, in which case
going to resolve to the same resource as the non-edit version, specifically the
resource returned by ``get_root()['joeschmoe']['photos']['photo1']``. But
traversal ends there; the ``photo1`` resource doesn't have an ``edit`` key.  In
fact, it might not even be a dictionary-like object, in which case
``photo1['edit']`` would be meaningless.  When the :app:`Pyramid` resource
location has been resolved to a *leaf* resource, but the entire request path
has not yet been expended, the *very next* path segment is treated as a
:term:`view name`.  The registry is then checked to see if a view of the
given name has been specified for a resource of the given type.  If so, the
view callable is invoked, with the resource passed in as the related
``context`` object (also available as ``request.context``).  If a view
callable could not be found, :app:`Pyramid` will return a "404 Not Found"
response.
:term:`view name`.  The registry is then checked to see if a view of the given
name has been specified for a resource of the given type.  If so, the view
callable is invoked, with the resource passed in as the related ``context``
object (also available as ``request.context``).  If a view callable could not
be found, :app:`Pyramid` will return a "404 Not Found" response.
You might conceptualize a request for ``/joeschmoe/photos/photo1/edit`` as
ultimately converted into the following piece of Pythonic pseudocode::
@@ -246,8 +242,8 @@
  view_callable(request)
The ``get_root`` and ``get_view`` functions don't really exist.  Internally,
:app:`Pyramid` does something more complicated.  But the example above
is a reasonable approximation of the view lookup algorithm in pseudocode.
:app:`Pyramid` does something more complicated.  But the example above is a
reasonable approximation of the view lookup algorithm in pseudocode.
Use Cases
---------
@@ -261,58 +257,57 @@
  /{userid}/{typename}/{objectid}[/{view_name}]
In all of the examples thus far, we've hard coded the typename value,
assuming that we'd know at development time what names were going to be used
("photos", "blog", etc.).  But what if we don't know what these names will
be?  Or, worse yet, what if we don't know *anything* about the structure of
the URLs inside a user's folder?  We could be writing a CMS where we want the
end user to be able to arbitrarily add content and other folders inside his
folder.  He might decide to nest folders dozens of layers deep.  How will you
construct matching patterns that could account for every possible combination
of paths that might develop?
In all of the examples thus far, we've hard coded the typename value, assuming
that we'd know at development time what names were going to be used ("photos",
"blog", etc.).  But what if we don't know what these names will be?  Or, worse
yet, what if we don't know *anything* about the structure of the URLs inside a
user's folder?  We could be writing a CMS where we want the end user to be able
to arbitrarily add content and other folders inside his folder.  He might
decide to nest folders dozens of layers deep.  How will you construct matching
patterns that could account for every possible combination of paths that might
develop?
It might be possible, but it certainly won't be easy.  The matching
patterns are going to become complex quickly as you try to handle all
of the edge cases.
It might be possible, but it certainly won't be easy.  The matching patterns
are going to become complex quickly as you try to handle all of the edge cases.
With traversal, however, it's straightforward.  Twenty layers of nesting
would be no problem.  :app:`Pyramid` will happily call ``__getitem__`` as
many times as it needs to, until it runs out of path segments or until a
resource raises a :exc:`KeyError`.  Each resource only needs to know how to
fetch its immediate children, the traversal algorithm takes care of the rest.
Also, since the structure of the resource tree can live in the database and
not in the code, it's simple to let users modify the tree at runtime to set
up their own personalized "directory" structures.
With traversal, however, it's straightforward.  Twenty layers of nesting would
be no problem.  :app:`Pyramid` will happily call ``__getitem__`` as many times
as it needs to, until it runs out of path segments or until a resource raises a
:exc:`KeyError`.  Each resource only needs to know how to fetch its immediate
children, and the traversal algorithm takes care of the rest. Also, since the
structure of the resource tree can live in the database and not in the code,
it's simple to let users modify the tree at runtime to set up their own
personalized "directory" structures.
Another use case in which traversal shines is when there is a need to support
a context-dependent security policy.  One example might be a document
management infrastructure for a large corporation, where members of different
departments have varying access levels to the various other departments'
files.  Reasonably, even specific files might need to be made available to
specific individuals.  Traversal does well here if your resources actually
represent the data objects related to your documents, because the idea of a
resource authorization is baked right into the code resolution and calling
process.  Resource objects can store ACLs, which can be inherited and/or
overridden by the subresources.
Another use case in which traversal shines is when there is a need to support a
context-dependent security policy.  One example might be a document management
infrastructure for a large corporation, where members of different departments
have varying access levels to the various other departments' files.
Reasonably, even specific files might need to be made available to specific
individuals.  Traversal does well here if your resources actually represent the
data objects related to your documents, because the idea of a resource
authorization is baked right into the code resolution and calling process.
Resource objects can store ACLs, which can be inherited and/or overridden by
the subresources.
If each resource can thus generate a context-based ACL, then whenever view
code is attempting to perform a sensitive action, it can check against that
ACL to see whether the current user should be allowed to perform the action.
In this way you achieve so called "instance based" or "row level" security
which is considerably harder to model using a traditional tabular approach.
If each resource can thus generate a context-based ACL, then whenever view code
is attempting to perform a sensitive action, it can check against that ACL to
see whether the current user should be allowed to perform the action. In this
way you achieve so called "instance based" or "row level" security which is
considerably harder to model using a traditional tabular approach.
:app:`Pyramid` actively supports such a scheme, and in fact if you register
your views with guard permissions and use an authorization policy,
:app:`Pyramid` can check against a resource's ACL when deciding whether or
not the view itself is available to the current user.
your views with guarded permissions and use an authorization policy,
:app:`Pyramid` can check against a resource's ACL when deciding whether or not
the view itself is available to the current user.
In summary, there are entire classes of problems that are more easily served
by traversal and view lookup than by :term:`URL dispatch`.  If your problems
don't require it, great: stick with :term:`URL dispatch`.  But if you're
using :app:`Pyramid` and you ever find that you *do* need to support one of
these use cases, you'll be glad you have traversal in your toolkit.
In summary, there are entire classes of problems that are more easily served by
traversal and view lookup than by :term:`URL dispatch`.  If your problems don't
require it, great, stick with :term:`URL dispatch`.  But if you're using
:app:`Pyramid` and you ever find that you *do* need to support one of these use
cases, you'll be glad you have traversal in your toolkit.
.. note::
   It is even possible to mix and match :term:`traversal` with
   :term:`URL dispatch` in the same :app:`Pyramid` application. See the
   It is even possible to mix and match :term:`traversal` with :term:`URL
   dispatch` in the same :app:`Pyramid` application. See the
   :ref:`hybrid_chapter` chapter for details.
docs/narr/renderers.rst
@@ -609,8 +609,8 @@
:ref:`Conflict Resolution <automatic_conflict_resolution>` mechanism. This
means that, in most cases, overriding a renderer is as simple as using the
:meth:`pyramid.config.Configurator.add_renderer` method to redefine the
template extension. For example, if you would like to override the ``.txt``
extension to specify a new renderer, you could do the following:
template extension. For example, if you would like to override the ``json``
renderer to specify a new renderer, you could do the following:
.. code-block:: python
docs/narr/resources.rst
@@ -3,50 +3,47 @@
Resources
=========
A :term:`resource` is an object that represents a "place" in a tree
related to your application.  Every :app:`Pyramid` application has at
least one resource object: the :term:`root` resource.  Even if you don't
define a root resource manually, a default one is created for you.  The
root resource is the root of a :term:`resource tree`.  A resource tree
is a set of nested dictionary-like objects which you can use to
represent your website's structure.
A :term:`resource` is an object that represents a "place" in a tree related to
your application.  Every :app:`Pyramid` application has at least one resource
object: the :term:`root` resource.  Even if you don't define a root resource
manually, a default one is created for you.  The root resource is the root of a
:term:`resource tree`.  A resource tree is a set of nested dictionary-like
objects which you can use to represent your website's structure.
In an application which uses :term:`traversal` to map URLs to code, the
resource tree structure is used heavily to map each URL to a :term:`view
callable`.  When :term:`traversal` is used, :app:`Pyramid` will walk
through the resource tree by traversing through its nested dictionary
structure in order to find a :term:`context` resource.  Once a context
resource is found, the context resource and data in the request will be
used to find a :term:`view callable`.
callable`.  When :term:`traversal` is used, :app:`Pyramid` will walk through
the resource tree by traversing through its nested dictionary structure in
order to find a :term:`context` resource.  Once a context resource is found,
the context resource and data in the request will be used to find a :term:`view
callable`.
In an application which uses :term:`URL dispatch`, the resource tree is only
used indirectly, and is often "invisible" to the developer.  In URL dispatch
applications, the resource "tree" is often composed of only the root resource
by itself.  This root resource sometimes has security declarations attached
to it, but is not required to have any.  In general, the resource tree is
much less important in applications that use URL dispatch than applications
that use traversal.
by itself.  This root resource sometimes has security declarations attached to
it, but is not required to have any.  In general, the resource tree is much
less important in applications that use URL dispatch than applications that use
traversal.
In "Zope-like" :app:`Pyramid` applications, resource objects also often store
data persistently, and offer methods related to mutating that persistent data.
In these kinds of applications, resources not only represent the site
structure of your website, but they become the :term:`domain model` of the
application.
In these kinds of applications, resources not only represent the site structure
of your website, but they become the :term:`domain model` of the application.
Also:
- The ``context`` and ``containment`` predicate arguments to
  :meth:`~pyramid.config.Configurator.add_view` (or a
  :func:`~pyramid.view.view_config` decorator) reference a resource class
  or resource :term:`interface`.
  :func:`~pyramid.view.view_config` decorator) reference a resource class or
  resource :term:`interface`.
- A :term:`root factory` returns a resource.
- A resource is exposed to :term:`view` code as the :term:`context` of a
  view.
- A resource is exposed to :term:`view` code as the :term:`context` of a view.
- Various helpful :app:`Pyramid` API methods expect a resource as an argument
  (e.g. :meth:`~pyramid.request.Request.resource_url` and others).
  (e.g., :meth:`~pyramid.request.Request.resource_url` and others).
.. index::
   single: resource tree
@@ -58,27 +55,26 @@
Defining a Resource Tree
------------------------
When :term:`traversal` is used (as opposed to a purely :term:`url dispatch`
When :term:`traversal` is used (as opposed to a purely :term:`URL dispatch`
based application), :app:`Pyramid` expects to be able to traverse a tree
composed of resources (the :term:`resource tree`).  Traversal begins at a
root resource, and descends into the tree recursively, trying each resource's
composed of resources (the :term:`resource tree`).  Traversal begins at a root
resource, and descends into the tree recursively, trying each resource's
``__getitem__`` method to resolve a path segment to another resource object.
:app:`Pyramid` imposes the following policy on resource instances in the
tree:
:app:`Pyramid` imposes the following policy on resource instances in the tree:
- A container resource (a resource which contains other resources) must
  supply a ``__getitem__`` method which is willing to resolve a unicode name
  to a sub-resource.  If a sub-resource by a particular name does not exist
  in a container resource, ``__getitem__`` method of the container resource
  must raise a :exc:`KeyError`.  If a sub-resource by that name *does* exist,
  the container's ``__getitem__`` should return the sub-resource.
- A container resource (a resource which contains other resources) must supply
  a ``__getitem__`` method which is willing to resolve a Unicode name to a
  sub-resource.  If a sub-resource by a particular name does not exist in a
  container resource, the ``__getitem__`` method of the container resource must
  raise a :exc:`KeyError`.  If a sub-resource by that name *does* exist, the
  container's ``__getitem__`` should return the sub-resource.
- Leaf resources, which do not contain other resources, must not implement a
  ``__getitem__``, or if they do, their ``__getitem__`` method must always
  raise a :exc:`KeyError`.
See :ref:`traversal_chapter` for more information about how traversal
works against resource instances.
See :ref:`traversal_chapter` for more information about how traversal works
against resource instances.
Here's a sample resource tree, represented by a variable named ``root``:
@@ -90,8 +86,8 @@
    root = Resource({'a':Resource({'b':Resource({'c':Resource()})})})
The resource tree we've created above is represented by a dictionary-like
root object which has a single child named ``'a'``.  ``'a'`` has a single child
The resource tree we've created above is represented by a dictionary-like root
object which has a single child named ``'a'``.  ``'a'`` has a single child
named ``'b'``, and ``'b'`` has a single child named ``'c'``, which has no
children. It is therefore possible to access the ``'c'`` leaf resource like so:
@@ -100,20 +96,20 @@
   root['a']['b']['c']
If you returned the above ``root`` object from a :term:`root factory`, the
path ``/a/b/c`` would find the ``'c'`` object in the resource tree as the
result of :term:`traversal`.
If you returned the above ``root`` object from a :term:`root factory`, the path
``/a/b/c`` would find the ``'c'`` object in the resource tree as the result of
:term:`traversal`.
In this example, each of the resources in the tree is of the same class.
This is not a requirement.  Resource elements in the tree can be of any type.
We used a single class to represent all resources in the tree for the sake of
In this example, each of the resources in the tree is of the same class. This
is not a requirement.  Resource elements in the tree can be of any type. We
used a single class to represent all resources in the tree for the sake of
simplicity, but in a "real" app, the resources in the tree can be arbitrary.
Although the example tree above can service a traversal, the resource
instances in the above example are not aware of :term:`location`, so their
utility in a "real" application is limited.  To make best use of built-in
:app:`Pyramid` API facilities, your resources should be "location-aware".
The next section details how to make resources location-aware.
Although the example tree above can service a traversal, the resource instances
in the above example are not aware of :term:`location`, so their utility in a
"real" application is limited.  To make best use of built-in :app:`Pyramid` API
facilities, your resources should be "location-aware". The next section details
how to make resources location-aware.
.. index::
   pair: location-aware; resource
@@ -125,16 +121,16 @@
In order for certain :app:`Pyramid` location, security, URL-generation, and
traversal APIs to work properly against the resources in a resource tree, all
resources in the tree must be :term:`location` -aware.  This means they must
resources in the tree must be :term:`location`-aware.  This means they must
have two attributes: ``__parent__`` and ``__name__``.
The ``__parent__`` attribute of a location-aware resource should be a
reference to the resource's parent resource instance in the tree.  The
``__name__`` attribute should be the name with which a resource's parent
refers to the resource via ``__getitem__``.
The ``__parent__`` attribute of a location-aware resource should be a reference
to the resource's parent resource instance in the tree.  The ``__name__``
attribute should be the name with which a resource's parent refers to the
resource via ``__getitem__``.
The ``__parent__`` of the root resource should be ``None`` and its
``__name__`` should be the empty string.  For instance:
The ``__parent__`` of the root resource should be ``None`` and its ``__name__``
should be the empty string.  For instance:
.. code-block:: python
   :linenos:
@@ -143,18 +139,18 @@
       __name__ = ''
       __parent__ = None
A resource returned from the root resource's ``__getitem__`` method should
have a ``__parent__`` attribute that is a reference to the root resource, and
its ``__name__`` attribute should match the name by which it is reachable via
the root resource's ``__getitem__``.  A container resource within the root
resource should have a ``__getitem__`` that returns resources with a
``__parent__`` attribute that points at the container, and these subobjects
should have a ``__name__`` attribute that matches the name by which they are
retrieved from the container via ``__getitem__``.  This pattern continues
recursively "up" the tree from the root.
A resource returned from the root resource's ``__getitem__`` method should have
a ``__parent__`` attribute that is a reference to the root resource, and its
``__name__`` attribute should match the name by which it is reachable via the
root resource's ``__getitem__``.  A container resource within the root resource
should have a ``__getitem__`` that returns resources with a ``__parent__``
attribute that points at the container, and these sub-objects should have a
``__name__`` attribute that matches the name by which they are retrieved from
the container via ``__getitem__``.  This pattern continues recursively "up" the
tree from the root.
The ``__parent__`` attributes of each resource form a linked list that points
"downwards" toward the root. This is analogous to the `..` entry in
"downwards" toward the root. This is analogous to the ``..`` entry in
filesystem directories. If you follow the ``__parent__`` values from any
resource in the resource tree, you will eventually come to the root resource,
just like if you keep executing the ``cd ..`` filesystem command, eventually
@@ -162,44 +158,41 @@
.. warning::
   If your root resource has a ``__name__`` argument that is not
   ``None`` or the empty string, URLs returned by the
   :func:`~pyramid.request.Request.resource_url` function and paths generated
   If your root resource has a ``__name__`` argument that is not ``None`` or
   the empty string, URLs returned by the
   :func:`~pyramid.request.Request.resource_url` function, and paths generated
   by the :func:`~pyramid.traversal.resource_path` and
   :func:`~pyramid.traversal.resource_path_tuple` APIs will be generated
   :func:`~pyramid.traversal.resource_path_tuple` APIs, will be generated
   improperly.  The value of ``__name__`` will be prepended to every path and
   URL generated (as opposed to a single leading slash or empty tuple
   element).
   URL generated (as opposed to a single leading slash or empty tuple element).
.. sidebar:: For your convenience
  If you'd rather not manage the ``__name__`` and ``__parent__`` attributes
  of your resources "by hand", an add-on package named
  If you'd rather not manage the ``__name__`` and ``__parent__`` attributes of
  your resources "by hand", an add-on package named
  :mod:`pyramid_traversalwrapper` can help.
  In order to use this helper feature, you must first install the
  :mod:`pyramid_traversalwrapper` package (available via PyPI), then register
  its ``ModelGraphTraverser`` as the traversal policy, rather than the
  default :app:`Pyramid` traverser. The package contains instructions for
  doing so.
  its ``ModelGraphTraverser`` as the traversal policy, rather than the default
  :app:`Pyramid` traverser. The package contains instructions for doing so.
  Once :app:`Pyramid` is configured with this feature, you will no longer
  need to manage the ``__parent__`` and ``__name__`` attributes on resource
  objects "by hand".  Instead, as necessary, during traversal :app:`Pyramid`
  will wrap each resource (even the root resource) in a ``LocationProxy``
  which will dynamically assign a ``__name__`` and a ``__parent__`` to the
  traversed resource (based on the last traversed resource and the name
  supplied to ``__getitem__``).  The root resource will have a ``__name__``
  attribute of ``None`` and a ``__parent__`` attribute of ``None``.
  Once :app:`Pyramid` is configured with this feature, you will no longer need
  to manage the ``__parent__`` and ``__name__`` attributes on resource objects
  "by hand".  Instead, as necessary during traversal, :app:`Pyramid` will wrap
  each resource (even the root resource) in a ``LocationProxy``, which will
  dynamically assign a ``__name__`` and a ``__parent__`` to the traversed
  resource, based on the last traversed resource and the name supplied to
  ``__getitem__``.  The root resource will have a ``__name__`` attribute of
  ``None`` and a ``__parent__`` attribute of ``None``.
Applications which use tree-walking :app:`Pyramid` APIs require
location-aware resources.  These APIs include (but are not limited to)
Applications which use tree-walking :app:`Pyramid` APIs require location-aware
resources.  These APIs include (but are not limited to)
:meth:`~pyramid.request.Request.resource_url`,
:func:`~pyramid.traversal.find_resource`,
:func:`~pyramid.traversal.find_root`,
:func:`~pyramid.traversal.find_resource`, :func:`~pyramid.traversal.find_root`,
:func:`~pyramid.traversal.find_interface`,
:func:`~pyramid.traversal.resource_path`,
:func:`~pyramid.traversal.resource_path_tuple`, or
:func:`~pyramid.traversal.resource_path_tuple`,
:func:`~pyramid.traversal.traverse`, :func:`~pyramid.traversal.virtual_root`,
and (usually) :meth:`~pyramid.request.Request.has_permission` and
:func:`~pyramid.security.principals_allowed_by_permission`.
@@ -214,15 +207,15 @@
.. _generating_the_url_of_a_resource:
Generating The URL Of A Resource
Generating the URL of a Resource
--------------------------------
If your resources are :term:`location` aware, you can use the
If your resources are :term:`location`-aware, you can use the
:meth:`pyramid.request.Request.resource_url` API to generate a URL for the
resource.  This URL will use the resource's position in the parent tree to
create a resource path, and it will prefix the path with the current
application URL to form a fully-qualified URL with the scheme, host, port,
and path.  You can also pass extra arguments to
application URL to form a fully-qualified URL with the scheme, host, port, and
path.  You can also pass extra arguments to
:meth:`~pyramid.request.Request.resource_url` to influence the generated URL.
The simplest call to :meth:`~pyramid.request.Request.resource_url` looks like
@@ -237,17 +230,17 @@
:term:`request` object.
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was
``example.com``, the URL generated would be ``http://example.com/``.
However, if the resource was a child of the root resource named ``a``, the
generated URL would be ``http://example.com/a/``.
resource, and the host that was used to contact the server was ``example.com``,
the URL generated would be ``http://example.com/``. However, if the resource
was a child of the root resource named ``a``, the generated URL would be
``http://example.com/a/``.
A slash is appended to all resource URLs when
:meth:`~pyramid.request.Request.resource_url` is used to generate them in
this simple manner, because resources are "places" in the hierarchy, and URLs
are meant to be clicked on to be visited.  Relative URLs that you include on
HTML pages rendered as the result of the default view of a resource are more
apt to be relative to these resources than relative to their parent.
:meth:`~pyramid.request.Request.resource_url` is used to generate them in this
simple manner, because resources are "places" in the hierarchy, and URLs are
meant to be clicked on to be visited.  Relative URLs that you include on HTML
pages rendered as the result of the default view of a resource are more apt to
be relative to these resources than relative to their parent.
You can also pass extra elements to
:meth:`~pyramid.request.Request.resource_url`:
@@ -258,12 +251,12 @@
   url = request.resource_url(resource, 'foo', 'bar')
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was
``example.com``, the URL generated would be ``http://example.com/foo/bar``.
Any number of extra elements can be passed to
:meth:`~pyramid.request.Request.resource_url` as extra positional arguments.
When extra elements are passed, they are appended to the resource's URL.  A
slash is not appended to the final segment when elements are passed.
resource, and the host that was used to contact the server was ``example.com``,
the URL generated would be ``http://example.com/foo/bar``. Any number of extra
elements can be passed to :meth:`~pyramid.request.Request.resource_url` as
extra positional arguments. When extra elements are passed, they are appended
to the resource's URL.  A slash is not appended to the final segment when
elements are passed.
You can also pass a query string:
@@ -273,16 +266,16 @@
   url = request.resource_url(resource, query={'a':'1'})
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was
``example.com``, the URL generated would be ``http://example.com/?a=1``.
resource, and the host that was used to contact the server was ``example.com``,
the URL generated would be ``http://example.com/?a=1``.
When a :term:`virtual root` is active, the URL generated by
:meth:`~pyramid.request.Request.resource_url` for a resource may be "shorter"
than its physical tree path.  See :ref:`virtual_root_support` for more
information about virtually rooting a resource.
For more information about generating resource URLs, see the documentation
for :meth:`pyramid.request.Request.resource_url`.
For more information about generating resource URLs, see the documentation for
:meth:`pyramid.request.Request.resource_url`.
.. index::
   pair: resource URL generation; overriding
@@ -292,10 +285,10 @@
Overriding Resource URL Generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If a resource object implements a ``__resource_url__`` method, this method
will be called when :meth:`~pyramid.request.Request.resource_url` is called
to generate a URL for the resource, overriding the default URL returned for
the resource by :meth:`~pyramid.request.Request.resource_url`.
If a resource object implements a ``__resource_url__`` method, this method will
be called when :meth:`~pyramid.request.Request.resource_url` is called to
generate a URL for the resource, overriding the default URL returned for the
resource by :meth:`~pyramid.request.Request.resource_url`.
The ``__resource_url__`` hook is passed two arguments: ``request`` and
``info``.  ``request`` is the :term:`request` object passed to
@@ -304,21 +297,21 @@
``physical_path``
   A string representing the "physical path" computed for the resource, as
   defined by ``pyramid.traversal.resource_path(resource)``.  It will begin
   and end with a slash.
   defined by ``pyramid.traversal.resource_path(resource)``.  It will begin and
   end with a slash.
``virtual_path``
   A string representing the "virtual path" computed for the resource, as
   defined by :ref:`virtual_root_support`.  This will be identical to the
   physical path if virtual rooting is not enabled.  It will begin and end
   with a slash.
   physical path if virtual rooting is not enabled.  It will begin and end with
   a slash.
``app_url``
  A string representing the application URL generated during
  ``request.resource_url``.  It will not end with a slash.  It represents a
  potentially customized URL prefix, containing potentially custom scheme,
  host and port information passed by the user to ``request.resource_url``.
  It should be preferred over use of ``request.application_url``.
  potentially customized URL prefix, containing potentially custom scheme, host
  and port information passed by the user to ``request.resource_url``.  It
  should be preferred over use of ``request.application_url``.
The ``__resource_url__`` method of a resource should return a string
representing a URL.  If it cannot override the default, it should return
@@ -335,12 +328,12 @@
The above example actually just generates and returns the default URL, which
would have been what was generated by the default ``resource_url`` machinery,
but your code can perform arbitrary logic as necessary.  For example, your
code may wish to override the hostname or port number of the generated URL.
but your code can perform arbitrary logic as necessary.  For example, your code
may wish to override the hostname or port number of the generated URL.
Note that the URL generated by ``__resource_url__`` should be fully
qualified, should end in a slash, and should not contain any query string or
anchor elements (only path elements) to work with
Note that the URL generated by ``__resource_url__`` should be fully qualified,
should end in a slash, and should not contain any query string or anchor
elements (only path elements) to work with
:meth:`~pyramid.request.Request.resource_url`.
.. index::
@@ -350,9 +343,8 @@
---------------------------------
:func:`pyramid.traversal.resource_path` returns a string object representing
the absolute physical path of the resource object based on its position in
the resource tree.  Each segment of the path is separated with a slash
character.
the absolute physical path of the resource object based on its position in the
resource tree.  Each segment of the path is separated with a slash character.
.. code-block:: python
   :linenos:
@@ -378,8 +370,8 @@
The resource passed in must be :term:`location`-aware.
The presence or absence of a :term:`virtual root` has no impact on the
behavior of :func:`~pyramid.traversal.resource_path`.
The presence or absence of a :term:`virtual root` has no impact on the behavior
of :func:`~pyramid.traversal.resource_path`.
.. index::
   pair: resource; finding by path
@@ -387,8 +379,8 @@
Finding a Resource by Path
--------------------------
If you have a string path to a resource, you can grab the resource from
that place in the application's resource tree using
If you have a string path to a resource, you can grab the resource from that
place in the application's resource tree using
:func:`pyramid.traversal.find_resource`.
You can resolve an absolute path by passing a string prefixed with a ``/`` as
@@ -400,8 +392,9 @@
   from pyramid.traversal import find_resource
   url = find_resource(anyresource, '/path')
Or you can resolve a path relative to the resource you pass in by passing a
string that isn't prefixed by ``/``:
Or you can resolve a path relative to the resource that you pass in to
:func:`pyramid.traversal.find_resource` by passing a string that isn't prefixed
by ``/``:
.. code-block:: python
   :linenos:
@@ -410,8 +403,8 @@
   url = find_resource(anyresource, 'path')
Often the paths you pass to :func:`~pyramid.traversal.find_resource` are
generated by the :func:`~pyramid.traversal.resource_path` API.  These APIs
are "mirrors" of each other.
generated by the :func:`~pyramid.traversal.resource_path` API.  These APIs are
"mirrors" of each other.
If the path cannot be resolved when calling
:func:`~pyramid.traversal.find_resource` (if the respective resource in the
@@ -427,10 +420,10 @@
-----------------------------------
:func:`pyramid.location.lineage` returns a generator representing the
:term:`lineage` of the :term:`location` aware :term:`resource` object.
:term:`lineage` of the :term:`location`-aware :term:`resource` object.
The :func:`~pyramid.location.lineage` function returns the resource it is
passed, then each parent of the resource, in order.  For example, if the
The :func:`~pyramid.location.lineage` function returns the resource that is
passed into it, then each parent of the resource in order.  For example, if the
resource tree is composed like so:
.. code-block:: python
@@ -451,18 +444,18 @@
   list(lineage(thing2))
   [ <Thing object at thing2>, <Thing object at thing1> ]
The generator returned by :func:`~pyramid.location.lineage` first returns the
resource it was passed unconditionally.  Then, if the resource supplied a
``__parent__`` attribute, it returns the resource represented by
``resource.__parent__``.  If *that* resource has a ``__parent__`` attribute,
return that resource's parent, and so on, until the resource being inspected
either has no ``__parent__`` attribute or has a ``__parent__`` attribute of
``None``.
The generator returned by :func:`~pyramid.location.lineage` first returns
unconditionally the resource that was passed into it.  Then, if the resource
supplied a ``__parent__`` attribute, it returns the resource represented by
``resource.__parent__``.  If *that* resource has a ``__parent__`` attribute, it
will return that resource's parent, and so on, until the resource being
inspected either has no ``__parent__`` attribute or has a ``__parent__``
attribute of ``None``.
See the documentation for :func:`pyramid.location.lineage` for more
information.
Determining if a Resource is In The Lineage of Another Resource
Determining if a Resource is in the Lineage of Another Resource
---------------------------------------------------------------
Use the :func:`pyramid.location.inside` function to determine if one resource
@@ -479,12 +472,12 @@
   b = Thing()
   b.__parent__ = a
Calling ``inside(b, a)`` will return ``True``, because ``b`` has a lineage
that includes ``a``.  However, calling ``inside(a, b)`` will return ``False``
Calling ``inside(b, a)`` will return ``True``, because ``b`` has a lineage that
includes ``a``.  However, calling ``inside(a, b)`` will return ``False``
because ``a`` does not have a lineage that includes ``b``.
The argument list for :func:`~pyramid.location.inside` is ``(resource1,
resource2)``.  ``resource1`` is 'inside' ``resource2`` if ``resource2`` is a
resource2)``.  ``resource1`` is "inside" ``resource2`` if ``resource2`` is a
:term:`lineage` ancestor of ``resource1``.  It is a lineage ancestor if its
parent (or one of its parent's parents, etc.) is an ancestor.
@@ -497,9 +490,9 @@
-------------------------
Use the :func:`pyramid.traversal.find_root` API to find the :term:`root`
resource.  The root resource is the root resource of the :term:`resource
tree`.  The API accepts a single argument: ``resource``.  This is a resource
that is :term:`location` aware.  It can be any resource in the tree for which
resource.  The root resource is the resource at the root of the :term:`resource
tree`. The API accepts a single argument: ``resource``.  This is a resource
that is :term:`location`-aware.  It can be any resource in the tree for which
you want to find the root.
For example, if the resource tree is:
@@ -518,9 +511,9 @@
The root resource is also available as ``request.root`` within :term:`view
callable` code.
The presence or absence of a :term:`virtual root` has no impact on the
behavior of :func:`~pyramid.traversal.find_root`.  The root object returned
is always the *physical* root object.
The presence or absence of a :term:`virtual root` has no impact on the behavior
of :func:`~pyramid.traversal.find_root`.  The root object returned is always
the *physical* root object.
.. index::
   single: resource interfaces
@@ -531,19 +524,18 @@
------------------------------------
Resources can optionally be made to implement an :term:`interface`.  An
interface is used to tag a resource object with a "type" that can later be
interface is used to tag a resource object with a "type" that later can be
referred to within :term:`view configuration` and by
:func:`pyramid.traversal.find_interface`.
Specifying an interface instead of a class as the ``context`` or
``containment`` predicate arguments within :term:`view configuration`
statements makes it possible to use a single view callable for more than one
class of resource object.  If your application is simple enough that you see
no reason to want to do this, you can skip reading this section of the
chapter.
class of resource objects.  If your application is simple enough that you see
no reason to want to do this, you can skip reading this section of the chapter.
For example, here's some code which describes a blog entry which also
declares that the blog entry implements an :term:`interface`.
For example, here's some code which describes a blog entry which also declares
that the blog entry implements an :term:`interface`.
.. code-block:: python
   :linenos:
@@ -577,10 +569,10 @@
``BlogEntry`` resource implements the ``IBlogEntry`` interface.
You can also specify that a particular resource *instance* provides an
interface, as opposed to its class.  When you declare that a class implements
an interface, all instances of that class will also provide that interface.
However, you can also just say that a single object provides the interface.
To do so, use the :func:`zope.interface.directlyProvides` function:
interface as opposed to its class.  When you declare that a class implements an
interface, all instances of that class will also provide that interface.
However, you can also just say that a single object provides the interface. To
do so, use the :func:`zope.interface.directlyProvides` function:
.. code-block:: python
   :linenos:
@@ -603,9 +595,9 @@
   directlyProvides(entry, IBlogEntry)
:func:`zope.interface.directlyProvides` will replace any existing interface
that was previously provided by an instance.  If a resource object already
has instance-level interface declarations that you don't want to replace, use
the :func:`zope.interface.alsoProvides` function:
that was previously provided by an instance.  If a resource object already has
instance-level interface declarations that you don't want to replace, use the
:func:`zope.interface.alsoProvides` function:
.. code-block:: python
   :linenos:
@@ -632,8 +624,8 @@
   directlyProvides(entry, IBlogEntry1)
   alsoProvides(entry, IBlogEntry2)
:func:`zope.interface.alsoProvides` will augment the set of interfaces
directly provided by an instance instead of overwriting them like
:func:`zope.interface.alsoProvides` will augment the set of interfaces directly
provided by an instance instead of overwriting them like
:func:`zope.interface.directlyProvides` does.
For more information about how resource interfaces can be used by view
@@ -642,7 +634,7 @@
.. index::
   pair: resource; finding by interface or class
Finding a Resource With a Class or Interface in Lineage
Finding a Resource with a Class or Interface in Lineage
-------------------------------------------------------
Use the :func:`~pyramid.traversal.find_interface` API to locate a parent that
@@ -662,18 +654,19 @@
Calling ``find_interface(a, Thing1)`` will return the ``a`` resource because
``a`` is of class ``Thing1`` (the resource passed as the first argument is
considered first, and is returned if the class or interface spec matches).
considered first, and is returned if the class or interface specification
matches).
Calling ``find_interface(b, Thing1)`` will return the ``a`` resource because
``a`` is of class ``Thing1`` and ``a`` is the first resource in ``b``'s
lineage of this class.
``a`` is of class ``Thing1`` and ``a`` is the first resource in ``b``'s lineage
of this class.
Calling ``find_interface(b, Thing2)`` will return the ``b`` resource.
The second argument to find_interface may also be a :term:`interface` instead
of a class.  If it is an interface, each resource in the lineage is checked
to see if the resource implements the specificed interface (instead of seeing
if the resource is of a class).
The second argument to ``find_interface`` may also be a :term:`interface`
instead of a class.  If it is an interface, each resource in the lineage is
checked to see if the resource implements the specificed interface (instead of
seeing if the resource is of a class).
.. seealso::
@@ -690,18 +683,17 @@
:ref:`traversal_chapter` and :ref:`urldispatch_chapter` for more information
about how a resource object becomes the context.
The APIs provided by :ref:`traversal_module` are used against resource
objects.  These functions can be used to find the "path" of a resource, the
root resource in a resource tree, or to generate a URL for a resource.
The APIs provided by :ref:`traversal_module` are used against resource objects.
These functions can be used to find the "path" of a resource, the root resource
in a resource tree, or to generate a URL for a resource.
The APIs provided by :ref:`location_module` are used against resources.
These can be used to walk down a resource tree, or conveniently locate one
resource "inside" another.
The APIs provided by :ref:`location_module` are used against resources. These
can be used to walk down a resource tree, or conveniently locate one resource
"inside" another.
Some APIs on the :class:`pyramid.request.Request` accept a resource object as a parameter.
For example, the :meth:`~pyramid.request.Request.has_permission` API accepts a
resource object as one of its arguments; the ACL is obtained from this
resource or one of its ancestors.  Other security related APIs on the
:class:`pyramid.request.Request` class also accept :term:`context` as an argument,
and a context is always a resource.
Some APIs on the :class:`pyramid.request.Request` accept a resource object as a
parameter. For example, the :meth:`~pyramid.request.Request.has_permission` API
accepts a resource object as one of its arguments; the ACL is obtained from
this resource or one of its ancestors.  Other security related APIs on the
:class:`pyramid.request.Request` class also accept :term:`context` as an
argument, and a context is always a resource.
docs/narr/scaffolding.rst
@@ -4,8 +4,8 @@
==========================
You can extend Pyramid by creating a :term:`scaffold` template.  A scaffold
template is useful if you'd like to distribute a customizable configuration
of Pyramid to other users.  Once you've created a scaffold, and someone has
template is useful if you'd like to distribute a customizable configuration of
Pyramid to other users.  Once you've created a scaffold, and someone has
installed the distribution that houses the scaffold, they can use the
``pcreate`` script to create a custom version of your scaffold's template.
Pyramid itself uses scaffolds to allow people to bootstrap new projects.  For
@@ -15,22 +15,22 @@
Basics
------
A scaffold template is just a bunch of source files and directories on disk.
A small definition class points at this directory; it is in turn pointed at
by a :term:`setuptools` "entry point" which registers the scaffold so it can
be found by the ``pcreate`` command.
A scaffold template is just a bunch of source files and directories on disk. A
small definition class points at this directory.  It is in turn pointed at by a
:term:`setuptools` "entry point" which registers the scaffold so it can be
found by the ``pcreate`` command.
To create a scaffold template, create a Python :term:`distribution` to house
the scaffold which includes a ``setup.py`` that relies on the ``setuptools``
package.  See `Creating a Package
<http://guide.python-distribute.org/creation.html>`_ for more information
about how to do this.  For the sake of example, we'll pretend the
distribution you create is named ``CoolExtension``, and it has a package
directory within it named ``coolextension``
<http://guide.python-distribute.org/creation.html>`_ for more information about
how to do this.  For example, we'll pretend the distribution you create is
named ``CoolExtension``, and it has a package directory within it named
``coolextension``.
Once you've created the distribution put a "scaffolds" directory within your
distribution's package directory, and create a file within that directory
named ``__init__.py`` with something like the following:
Once you've created the distribution, put a "scaffolds" directory within your
distribution's package directory, and create a file within that directory named
``__init__.py`` with something like the following:
.. code-block:: python
   :linenos:
@@ -54,12 +54,12 @@
  the string value of the variable named ``var`` provided to the scaffold.
- Files and directories with filenames that contain the string ``+var+`` will
  have that string replaced with the value of the ``var`` variable provided
  to the scaffold.
  have that string replaced with the value of the ``var`` variable provided to
  the scaffold.
- Files that start with a dot (e.g., ``.env``) are ignored and will not be
  copied over to the destination directory. If you want to include a file with
  a leading dot then you must replace the dot with ``+dot+`` (e.g.,
  a leading dot, then you must replace the dot with ``+dot+`` (e.g.,
  ``+dot+env``).
Otherwise, files and directories which live in the template directory will be
@@ -67,14 +67,14 @@
The variables provided by the default ``PyramidTemplate`` include ``project``
(the project name provided by the user as an argument to ``pcreate``),
``package`` (a lowercasing and normalizing of the project name provided by
the user), ``random_string`` (a long random string), and ``package_logger``
(the name of the package's logger).
``package`` (a lowercasing and normalizing of the project name provided by the
user), ``random_string`` (a long random string), and ``package_logger`` (the
name of the package's logger).
See Pyramid's "scaffolds" package
(https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for
concrete examples of scaffold directories (``zodb``, ``alchemy``, and
``starter``, for example).
(https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for concrete
examples of scaffold directories (``zodb``, ``alchemy``, and ``starter``, for
example).
After you've created the template directory, add the following to the
``entry_points`` value of your distribution's ``setup.py``:
@@ -96,17 +96,16 @@
          """
        )
Run your distribution's ``setup.py develop`` or ``setup.py install``
command. After that, you should be able to see your scaffolding template
listed when you run ``pcreate -l``.  It will be named ``coolextension``
because that's the name we gave it in the entry point setup.  Running
``pcreate -s coolextension MyStuff`` will then render your scaffold to an
output directory named ``MyStuff``.
Run your distribution's ``setup.py develop`` or ``setup.py install`` command.
After that, you should be able to see your scaffolding template listed when you
run ``pcreate -l``.  It will be named ``coolextension`` because that's the name
we gave it in the entry point setup.  Running ``pcreate -s coolextension
MyStuff`` will then render your scaffold to an output directory named
``MyStuff``.
See the module documentation for :mod:`pyramid.scaffolds` for information
about the API of the :class:`pyramid.scaffolds.Template` class and
related classes.  You can override methods of this class to get special
behavior.
See the module documentation for :mod:`pyramid.scaffolds` for information about
the API of the :class:`pyramid.scaffolds.Template` class and related classes.
You can override methods of this class to get special behavior.
Supporting Older Pyramid Versions
---------------------------------
@@ -139,21 +138,22 @@
And then in the setup.py of the package that contains your scaffold, define
the template as a target of both ``paste.paster_create_template`` (for
``paster create``) and ``pyramid.scaffold`` (for ``pcreate``)::
``paster create``) and ``pyramid.scaffold`` (for ``pcreate``).
      [paste.paster_create_template]
      coolextension=coolextension.scaffolds:CoolExtensionTemplate
      [pyramid.scaffold]
      coolextension=coolextension.scaffolds:CoolExtensionTemplate
.. code-block:: ini
Doing this hideousness will allow your scaffold to work as a ``paster
create`` target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under
1.3).  If an invoker tries to run ``paster create`` against a scaffold
defined this way under 1.3, an error is raised instructing them to use
``pcreate`` instead.
    [paste.paster_create_template]
    coolextension=coolextension.scaffolds:CoolExtensionTemplate
    [pyramid.scaffold]
    coolextension=coolextension.scaffolds:CoolExtensionTemplate
If you want only to support Pyramid 1.3 only, it's much cleaner, and the API
is stable:
Doing this hideousness will allow your scaffold to work as a ``paster create``
target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under 1.3).  If an
invoker tries to run ``paster create`` against a scaffold defined this way
under 1.3, an error is raised instructing them to use ``pcreate`` instead.
If you want to support Pyramid 1.3 only, it's much cleaner, and the API is
stable:
.. code-block:: python
   :linenos:
@@ -164,17 +164,17 @@
       _template_dir = 'coolextension_scaffold'
       summary = 'My cool_extension'
You only need to specify a ``paste.paster_create_template`` entry point
target in your ``setup.py`` if you want your scaffold to be consumable by
users of Pyramid 1.0, 1.1, or 1.2.  To support only 1.3, specifying only the
You only need to specify a ``paste.paster_create_template`` entry point target
in your ``setup.py`` if you want your scaffold to be consumable by users of
Pyramid 1.0, 1.1, or 1.2.  To support only 1.3, specifying only the
``pyramid.scaffold`` entry point is good enough.  If you want to support both
``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2
and some older version), you'll need to define both.
``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2 and
some older version), you'll need to define both.
Examples
--------
Existing third-party distributions which house scaffolding are available via
:term:`PyPI`.  The ``pyramid_jqm``, ``pyramid_zcml`` and ``pyramid_jinja2``
:term:`PyPI`.  The ``pyramid_jqm``, ``pyramid_zcml``, and ``pyramid_jinja2``
packages house scaffolds.  You can install and examine these packages to see
how they work in the quest to develop your own scaffolding.
docs/narr/security.rst
@@ -6,64 +6,59 @@
Security
========
:app:`Pyramid` provides an optional, declarative, security system.
Security in :app:`Pyramid` is separated into authentication and
authorization. The two systems communicate via :term:`principal`
identifiers. Authentication is merely the mechanism by which credentials
provided in the :term:`request` are resolved to one or more
:term:`principal` identifiers. These identifiers represent the users and
groups that are in effect during the request. Authorization then determines
access based on the :term:`principal` identifiers, the requested
:app:`Pyramid` provides an optional, declarative, security system. Security in
:app:`Pyramid` is separated into authentication and authorization. The two
systems communicate via :term:`principal` identifiers. Authentication is merely
the mechanism by which credentials provided in the :term:`request` are resolved
to one or more :term:`principal` identifiers. These identifiers represent the
users and groups that are in effect during the request. Authorization then
determines access based on the :term:`principal` identifiers, the requested
:term:`permission`, and a :term:`context`.
The :app:`Pyramid` authorization system
can prevent a :term:`view` from being invoked based on an
:term:`authorization policy`. Before a view is invoked, the
authorization system can use the credentials in the :term:`request`
along with the :term:`context` resource to determine if access will be
allowed.  Here's how it works at a high level:
The :app:`Pyramid` authorization system can prevent a :term:`view` from being
invoked based on an :term:`authorization policy`. Before a view is invoked, the
authorization system can use the credentials in the :term:`request` along with
the :term:`context` resource to determine if access will be allowed.  Here's
how it works at a high level:
- A user may or may not have previously visited the application and
  supplied authentication credentials, including a :term:`userid`.  If
  so, the application may have called
  :func:`pyramid.security.remember` to remember these.
- A user may or may not have previously visited the application and supplied
  authentication credentials, including a :term:`userid`.  If so, the
  application may have called :func:`pyramid.security.remember` to remember
  these.
- A :term:`request` is generated when a user visits the application.
- Based on the request, a :term:`context` resource is located through
  :term:`resource location`.  A context is located differently depending on
  whether the application uses :term:`traversal` or :term:`URL dispatch`, but
  a context is ultimately found in either case.  See
  the :ref:`urldispatch_chapter` chapter for more information.
  whether the application uses :term:`traversal` or :term:`URL dispatch`, but a
  context is ultimately found in either case.  See the
  :ref:`urldispatch_chapter` chapter for more information.
- A :term:`view callable` is located by :term:`view lookup` using the
  context as well as other attributes of the request.
- A :term:`view callable` is located by :term:`view lookup` using the context
  as well as other attributes of the request.
- If an :term:`authentication policy` is in effect, it is passed the
  request. It will return some number of :term:`principal` identifiers.
  To do this, the policy would need to determine the authenticated
  :term:`userid` present in the request.
- If an :term:`authentication policy` is in effect, it is passed the request.
  It will return some number of :term:`principal` identifiers. To do this, the
  policy would need to determine the authenticated :term:`userid` present in
  the request.
- If an :term:`authorization policy` is in effect and the :term:`view
  configuration` associated with the view callable that was found has
  a :term:`permission` associated with it, the authorization policy is
  passed the :term:`context`, some number of :term:`principal`
  identifiers returned by the authentication policy, and the
  :term:`permission` associated with the view; it will allow or deny
  access.
  configuration` associated with the view callable that was found has a
  :term:`permission` associated with it, the authorization policy is passed the
  :term:`context`, some number of :term:`principal` identifiers returned by the
  authentication policy, and the :term:`permission` associated with the view;
  it will allow or deny access.
- If the authorization policy allows access, the view callable is
  invoked.
- If the authorization policy allows access, the view callable is invoked.
- If the authorization policy denies access, the view callable is not
  invoked; instead the :term:`forbidden view` is invoked.
- If the authorization policy denies access, the view callable is not invoked.
  Instead the :term:`forbidden view` is invoked.
Authorization is enabled by modifying your application to include an
:term:`authentication policy` and :term:`authorization policy`.
:app:`Pyramid` comes with a variety of implementations of these
policies.  To provide maximal flexibility, :app:`Pyramid` also
allows you to create custom authentication policies and authorization
policies.
:term:`authentication policy` and :term:`authorization policy`. :app:`Pyramid`
comes with a variety of implementations of these policies.  To provide maximal
flexibility, :app:`Pyramid` also allows you to create custom authentication
policies and authorization policies.
.. index::
   single: authorization policy
@@ -73,23 +68,22 @@
Enabling an Authorization Policy
--------------------------------
:app:`Pyramid` does not enable any authorization policy by default.  All
views are accessible by completely anonymous users.  In order to begin
protecting views from execution based on security settings, you need
to enable an authorization policy.
:app:`Pyramid` does not enable any authorization policy by default.  All views
are accessible by completely anonymous users.  In order to begin protecting
views from execution based on security settings, you need to enable an
authorization policy.
Enabling an Authorization Policy Imperatively
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the :meth:`~pyramid.config.Configurator.set_authorization_policy` method
of the :class:`~pyramid.config.Configurator` to enable an authorization
policy.
Use the :meth:`~pyramid.config.Configurator.set_authorization_policy` method of
the :class:`~pyramid.config.Configurator` to enable an authorization policy.
You must also enable an :term:`authentication policy` in order to enable the
authorization policy.  This is because authorization, in general, depends
upon authentication.  Use the
:meth:`~pyramid.config.Configurator.set_authentication_policy` method
during application setup to specify the authentication policy.
authorization policy.  This is because authorization, in general, depends upon
authentication.  Use the
:meth:`~pyramid.config.Configurator.set_authentication_policy` method during
application setup to specify the authentication policy.
For example:
@@ -105,28 +99,27 @@
   config.set_authentication_policy(authn_policy)
   config.set_authorization_policy(authz_policy)
.. note:: The ``authentication_policy`` and ``authorization_policy``
   arguments may also be passed to their respective methods mentioned above
   as :term:`dotted Python name` values, each representing the dotted name
   path to a suitable implementation global defined at Python module scope.
.. note:: The ``authentication_policy`` and ``authorization_policy`` arguments
   may also be passed to their respective methods mentioned above as
   :term:`dotted Python name` values, each representing the dotted name path to
   a suitable implementation global defined at Python module scope.
The above configuration enables a policy which compares the value of an "auth
ticket" cookie passed in the request's environment which contains a reference
to a single :term:`userid` and matches that userid's
:term:`principals <principal>` against the principals present in any
:term:`ACL` found in the resource tree when attempting to call some
:term:`view`.
to a single :term:`userid`, and matches that userid's :term:`principals
<principal>` against the principals present in any :term:`ACL` found in the
resource tree when attempting to call some :term:`view`.
While it is possible to mix and match different authentication and
authorization policies, it is an error to configure a Pyramid application
with an authentication policy but without the authorization policy or vice
versa.  If you do this, you'll receive an error at application startup time.
authorization policies, it is an error to configure a Pyramid application with
an authentication policy but without the authorization policy or vice versa. If
you do this, you'll receive an error at application startup time.
.. seealso::
    See also the :mod:`pyramid.authorization` and
    :mod:`pyramid.authentication` modules for alternate implementations of
    authorization and authentication policies.
    See also the :mod:`pyramid.authorization` and :mod:`pyramid.authentication`
    modules for alternative implementations of authorization and authentication
    policies.
.. index::
   single: permissions
@@ -139,14 +132,13 @@
To protect a :term:`view callable` from invocation based on a user's security
settings when a particular type of resource becomes the :term:`context`, you
must pass a :term:`permission` to :term:`view configuration`.  Permissions
are usually just strings, and they have no required composition: you can name
must pass a :term:`permission` to :term:`view configuration`.  Permissions are
usually just strings, and they have no required composition: you can name
permissions whatever you like.
For example, the following view declaration protects the view named
``add_entry.html`` when the context resource is of type ``Blog`` with the
``add`` permission using the :meth:`pyramid.config.Configurator.add_view`
API:
``add`` permission using the :meth:`pyramid.config.Configurator.add_view` API:
.. code-block:: python
   :linenos:
@@ -158,8 +150,8 @@
                   context='mypackage.resources.Blog',
                   permission='add')
The equivalent view registration including the ``add`` permission name
may be performed via the ``@view_config`` decorator:
The equivalent view registration including the ``add`` permission name may be
performed via the ``@view_config`` decorator:
.. code-block:: python
   :linenos:
@@ -173,11 +165,11 @@
       pass
As a result of any of these various view configuration statements, if an
authorization policy is in place when the view callable is found during
normal application operations, the requesting user will need to possess the
``add`` permission against the :term:`context` resource in order to be able
to invoke the ``blog_entry_add_view`` view.  If he does not, the
:term:`Forbidden view` will be invoked.
authorization policy is in place when the view callable is found during normal
application operations, the requesting user will need to possess the ``add``
permission against the :term:`context` resource in order to be able to invoke
the ``blog_entry_add_view`` view.  If they do not, the :term:`Forbidden view`
will be invoked.
.. index::
   pair: permission; default
@@ -187,18 +179,17 @@
Setting a Default Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If a permission is not supplied to a view configuration, the registered
view will always be executable by entirely anonymous users: any
authorization policy in effect is ignored.
If a permission is not supplied to a view configuration, the registered view
will always be executable by entirely anonymous users: any authorization policy
in effect is ignored.
In support of making it easier to configure applications which are
"secure by default", :app:`Pyramid` allows you to configure a
*default* permission.  If supplied, the default permission is used as
the permission string to all view registrations which don't otherwise
name a ``permission`` argument.
In support of making it easier to configure applications which are "secure by
default", :app:`Pyramid` allows you to configure a *default* permission.  If
supplied, the default permission is used as the permission string to all view
registrations which don't otherwise name a ``permission`` argument.
The :meth:`pyramid.config.Configurator.set_default_permission` method
supports configuring a default permission for an application.
The :meth:`pyramid.config.Configurator.set_default_permission` method supports
configuring a default permission for an application.
When a default permission is registered:
@@ -207,8 +198,8 @@
  view-configuration-named permission is used.
- If a view configuration names the permission
  :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission
  is ignored, and the view is registered *without* a permission (making it
  :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission is
  ignored, and the view is registered *without* a permission (making it
  available to all callers regardless of their credentials).
.. warning::
@@ -226,19 +217,18 @@
.. _assigning_acls:
Assigning ACLs to your Resource Objects
Assigning ACLs to Your Resource Objects
---------------------------------------
When the default :app:`Pyramid` :term:`authorization policy` determines
whether a user possesses a particular permission with respect to a resource,
it examines the :term:`ACL` associated with the resource.  An ACL is
associated with a resource by adding an ``__acl__`` attribute to the resource
object.  This attribute can be defined on the resource *instance* if you need
When the default :app:`Pyramid` :term:`authorization policy` determines whether
a user possesses a particular permission with respect to a resource, it
examines the :term:`ACL` associated with the resource.  An ACL is associated
with a resource by adding an ``__acl__`` attribute to the resource object.
This attribute can be defined on the resource *instance* if you need
instance-level security, or it can be defined on the resource *class* if you
just need type-level security.
For example, an ACL might be attached to the resource for a blog via its
class:
For example, an ACL might be attached to the resource for a blog via its class:
.. code-block:: python
   :linenos:
@@ -273,11 +263,11 @@
           (Allow, 'group:editors', 'edit'),
           ]
Whether an ACL is attached to a resource's class or an instance of the
resource itself, the effect is the same.  It is useful to decorate individual
resource instances with an ACL (as opposed to just decorating their class) in
applications such as "CMS" systems where fine-grained access is required on
an object-by-object basis.
Whether an ACL is attached to a resource's class or an instance of the resource
itself, the effect is the same.  It is useful to decorate individual resource
instances with an ACL (as opposed to just decorating their class) in
applications such as content management systems where fine-grained access is
required on an object-by-object basis.
Dynamic ACLs are also possible by turning the ACL into a callable on the
resource. This may allow the ACL to dynamically generate rules based on
@@ -321,30 +311,27 @@
           (Allow, 'group:editors', 'edit'),
           ]
The example ACL indicates that the
:data:`pyramid.security.Everyone` principal -- a special
system-defined principal indicating, literally, everyone -- is allowed
to view the blog, the ``group:editors`` principal is allowed to add to
and edit the blog.
The example ACL indicates that the :data:`pyramid.security.Everyone`
principal—a special system-defined principal indicating, literally, everyone—is
allowed to view the blog, and the ``group:editors`` principal is allowed to add
to and edit the blog.
Each element of an ACL is an :term:`ACE` or access control entry.
For example, in the above code block, there are three ACEs: ``(Allow,
Everyone, 'view')``, ``(Allow, 'group:editors', 'add')``, and
``(Allow, 'group:editors', 'edit')``.
Each element of an ACL is an :term:`ACE`, or access control entry. For example,
in the above code block, there are three ACEs: ``(Allow, Everyone, 'view')``,
``(Allow, 'group:editors', 'add')``, and ``(Allow, 'group:editors', 'edit')``.
The first element of any ACE is either
:data:`pyramid.security.Allow`, or
:data:`pyramid.security.Deny`, representing the action to take when
the ACE matches.  The second element is a :term:`principal`.  The
third argument is a permission or sequence of permission names.
The first element of any ACE is either :data:`pyramid.security.Allow`, or
:data:`pyramid.security.Deny`, representing the action to take when the ACE
matches.  The second element is a :term:`principal`.  The third argument is a
permission or sequence of permission names.
A principal is usually a user id, however it also may be a group id if your
authentication system provides group information and the effective
:term:`authentication policy` policy is written to respect group information.
See :ref:`extending_default_authentication_policies`.
Each ACE in an ACL is processed by an authorization policy *in the
order dictated by the ACL*.  So if you have an ACL like this:
Each ACE in an ACL is processed by an authorization policy *in the order
dictated by the ACL*.  So if you have an ACL like this:
.. code-block:: python
   :linenos:
@@ -358,10 +345,9 @@
       (Deny, Everyone, 'view'),
       ]
The default authorization policy will *allow* everyone the view
permission, even though later in the ACL you have an ACE that denies
everyone the view permission.  On the other hand, if you have an ACL
like this:
The default authorization policy will *allow* everyone the view permission,
even though later in the ACL you have an ACE that denies everyone the view
permission.  On the other hand, if you have an ACL like this:
.. code-block:: python
   :linenos:
@@ -375,14 +361,13 @@
       (Allow, Everyone, 'view'),
       ]
The authorization policy will deny everyone the view permission, even
though later in the ACL is an ACE that allows everyone.
The authorization policy will deny everyone the view permission, even though
later in the ACL, there is an ACE that allows everyone.
The third argument in an ACE can also be a sequence of permission
names instead of a single permission name.  So instead of creating
multiple ACEs representing a number of different permission grants to
a single ``group:editors`` group, we can collapse this into a single
ACE, as below.
The third argument in an ACE can also be a sequence of permission names instead
of a single permission name.  So instead of creating multiple ACEs representing
a number of different permission grants to a single ``group:editors`` group, we
can collapse this into a single ACE, as below.
.. code-block:: python
   :linenos:
@@ -403,23 +388,21 @@
Special Principal Names
-----------------------
Special principal names exist in the :mod:`pyramid.security`
module.  They can be imported for use in your own code to populate
ACLs, e.g. :data:`pyramid.security.Everyone`.
Special principal names exist in the :mod:`pyramid.security` module.  They can
be imported for use in your own code to populate ACLs, e.g.,
:data:`pyramid.security.Everyone`.
:data:`pyramid.security.Everyone`
  Literally, everyone, no matter what.  This object is actually a
  string "under the hood" (``system.Everyone``).  Every user "is" the
  principal named Everyone during every request, even if a security
  policy is not in use.
  Literally, everyone, no matter what.  This object is actually a string under
  the hood (``system.Everyone``).  Every user *is* the principal named
  "Everyone" during every request, even if a security policy is not in use.
:data:`pyramid.security.Authenticated`
  Any user with credentials as determined by the current security
  policy.  You might think of it as any user that is "logged in".
  This object is actually a string "under the hood"
  (``system.Authenticated``).
  Any user with credentials as determined by the current security policy.  You
  might think of it as any user that is "logged in".  This object is actually a
  string under the hood (``system.Authenticated``).
.. index::
   single: permission names
@@ -428,19 +411,19 @@
Special Permissions
-------------------
Special permission names exist in the :mod:`pyramid.security`
module.  These can be imported for use in ACLs.
Special permission names exist in the :mod:`pyramid.security` module.  These
can be imported for use in ACLs.
.. _all_permissions:
:data:`pyramid.security.ALL_PERMISSIONS`
  An object representing, literally, *all* permissions.  Useful in an
  ACL like so: ``(Allow, 'fred', ALL_PERMISSIONS)``.  The
  ``ALL_PERMISSIONS`` object is actually a stand-in object that has a
  ``__contains__`` method that always returns ``True``, which, for all
  known authorization policies, has the effect of indicating that a
  given principal "has" any permission asked for by the system.
  An object representing, literally, *all* permissions.  Useful in an ACL like
  so: ``(Allow, 'fred', ALL_PERMISSIONS)``.  The ``ALL_PERMISSIONS`` object is
  actually a stand-in object that has a ``__contains__`` method that always
  returns ``True``, which, for all known authorization policies, has the effect
  of indicating that a given principal has any permission asked for by the
  system.
.. index::
   single: special ACE
@@ -451,11 +434,11 @@
A convenience :term:`ACE` is defined representing a deny to everyone of all
permissions in :data:`pyramid.security.DENY_ALL`.  This ACE is often used as
the *last* ACE of an ACL to explicitly cause inheriting authorization
policies to "stop looking up the traversal tree" (effectively breaking any
inheritance).  For example, an ACL which allows *only* ``fred`` the view
permission for a particular resource despite what inherited ACLs may say when
the default authorization policy is in effect might look like so:
the *last* ACE of an ACL to explicitly cause inheriting authorization policies
to "stop looking up the traversal tree" (effectively breaking any inheritance).
For example, an ACL which allows *only* ``fred`` the view permission for a
particular resource, despite what inherited ACLs may say when the default
authorization policy is in effect, might look like so:
.. code-block:: python
   :linenos:
@@ -465,8 +448,8 @@
   __acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ]
"Under the hood", the :data:`pyramid.security.DENY_ALL` ACE equals
the following:
Under the hood, the :data:`pyramid.security.DENY_ALL` ACE equals the
following:
.. code-block:: python
   :linenos:
@@ -483,14 +466,14 @@
While the default :term:`authorization policy` is in place, if a resource
object does not have an ACL when it is the context, its *parent* is consulted
for an ACL.  If that object does not have an ACL, *its* parent is consulted
for an ACL, ad infinitum, until we've reached the root and there are no more
for an ACL.  If that object does not have an ACL, *its* parent is consulted for
an ACL, ad infinitum, until we've reached the root and there are no more
parents left.
In order to allow the security machinery to perform ACL inheritance, resource
objects must provide *location-awareness*.  Providing *location-awareness*
means two things: the root object in the resource tree must have a
``__name__`` attribute and a ``__parent__`` attribute.
means two things: the root object in the resource tree must have a ``__name__``
attribute and a ``__parent__`` attribute.
.. code-block:: python
   :linenos:
@@ -499,10 +482,10 @@
       __name__ = ''
       __parent__ = None
An object with a ``__parent__`` attribute and a ``__name__`` attribute
is said to be *location-aware*.  Location-aware objects define an
``__parent__`` attribute which points at their parent object.  The
root object's ``__parent__`` is ``None``.
An object with a ``__parent__`` attribute and a ``__name__`` attribute is said
to be *location-aware*.  Location-aware objects define a ``__parent__``
attribute which points at their parent object.  The root object's
``__parent__`` is ``None``.
.. seealso::
@@ -519,12 +502,11 @@
Changing the Forbidden View
---------------------------
When :app:`Pyramid` denies a view invocation due to an
authorization denial, the special ``forbidden`` view is invoked.  "Out
of the box", this forbidden view is very plain.  See
:ref:`changing_the_forbidden_view` within :ref:`hooks_chapter` for
instructions on how to create a custom forbidden view and arrange for
it to be called when view authorization is denied.
When :app:`Pyramid` denies a view invocation due to an authorization denial,
the special ``forbidden`` view is invoked.  Out of the box, this forbidden view
is very plain.  See :ref:`changing_the_forbidden_view` within
:ref:`hooks_chapter` for instructions on how to create a custom forbidden view
and arrange for it to be called when view authorization is denied.
.. index::
   single: debugging authorization failures
@@ -534,8 +516,8 @@
Debugging View Authorization Failures
-------------------------------------
If your application in your judgment is allowing or denying view
access inappropriately, start your application under a shell using the
If your application in your judgment is allowing or denying view access
inappropriately, start your application under a shell using the
``PYRAMID_DEBUG_AUTHORIZATION`` environment variable set to ``1``.  For
example:
@@ -543,14 +525,13 @@
  $ PYRAMID_DEBUG_AUTHORIZATION=1 $VENV/bin/pserve myproject.ini
When any authorization takes place during a top-level view rendering,
a message will be logged to the console (to stderr) about what ACE in
which ACL permitted or denied the authorization based on
authentication information.
When any authorization takes place during a top-level view rendering, a message
will be logged to the console (to stderr) about what ACE in which ACL permitted
or denied the authorization based on authentication information.
This behavior can also be turned on in the application ``.ini`` file
by setting the ``pyramid.debug_authorization`` key to ``true`` within the
application's configuration section, e.g.:
This behavior can also be turned on in the application ``.ini`` file by setting
the ``pyramid.debug_authorization`` key to ``true`` within the application's
configuration section, e.g.:
.. code-block:: ini
  :linenos:
@@ -559,26 +540,24 @@
  use = egg:MyProject
  pyramid.debug_authorization = true
With this debug flag turned on, the response sent to the browser will
also contain security debugging information in its body.
With this debug flag turned on, the response sent to the browser will also
contain security debugging information in its body.
Debugging Imperative Authorization Failures
-------------------------------------------
The :meth:`pyramid.request.Request.has_permission` API is used to check
security within view functions imperatively.  It returns instances of
objects that are effectively booleans.  But these objects are not raw
``True`` or ``False`` objects, and have information attached to them
about why the permission was allowed or denied.  The object will be
one of :data:`pyramid.security.ACLAllowed`,
:data:`pyramid.security.ACLDenied`,
:data:`pyramid.security.Allowed`, or
:data:`pyramid.security.Denied`, as documented in
:ref:`security_module`.  At the very minimum these objects will have a
``msg`` attribute, which is a string indicating why the permission was
denied or allowed.  Introspecting this information in the debugger or
via print statements when a call to
:meth:`~pyramid.request.Request.has_permission` fails is often useful.
security within view functions imperatively.  It returns instances of objects
that are effectively booleans.  But these objects are not raw ``True`` or
``False`` objects, and have information attached to them about why the
permission was allowed or denied.  The object will be one of
:data:`pyramid.security.ACLAllowed`, :data:`pyramid.security.ACLDenied`,
:data:`pyramid.security.Allowed`, or :data:`pyramid.security.Denied`, as
documented in :ref:`security_module`.  At the very minimum, these objects will
have a ``msg`` attribute, which is a string indicating why the permission was
denied or allowed.  Introspecting this information in the debugger or via print
statements when a call to :meth:`~pyramid.request.Request.has_permission` fails
is often useful.
.. index::
   single: authentication policy (extending)
@@ -588,27 +567,26 @@
Extending Default Authentication Policies
-----------------------------------------
Pyramid ships with some builtin authentication policies for use in your
applications. See :mod:`pyramid.authentication` for the available
policies. They differ on their mechanisms for tracking authentication
credentials between requests, however they all interface with your
application in mostly the same way.
Pyramid ships with some built in authentication policies for use in your
applications. See :mod:`pyramid.authentication` for the available policies.
They differ on their mechanisms for tracking authentication credentials between
requests, however they all interface with your application in mostly the same
way.
Above you learned about :ref:`assigning_acls`. Each :term:`principal` used
in the :term:`ACL` is matched against the list returned from
Above you learned about :ref:`assigning_acls`. Each :term:`principal` used in
the :term:`ACL` is matched against the list returned from
:meth:`pyramid.interfaces.IAuthenticationPolicy.effective_principals`.
Similarly, :meth:`pyramid.request.Request.authenticated_userid` maps to
:meth:`pyramid.interfaces.IAuthenticationPolicy.authenticated_userid`.
You may control these values by subclassing the default authentication
policies. For example, below we subclass the
:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and define
extra functionality to query our database before confirming that the
:term:`userid` is valid in order to avoid blindly trusting the value in the
cookie (what if the cookie is still valid but the user has deleted their
account?). We then use that :term:`userid` to augment the
``effective_principals`` with information about groups and other state for
that user.
:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and define extra
functionality to query our database before confirming that the :term:`userid`
is valid in order to avoid blindly trusting the value in the cookie (what if
the cookie is still valid, but the user has deleted their account?).  We then
use that :term:`userid` to augment the ``effective_principals`` with
information about groups and other state for that user.
.. code-block:: python
   :linenos:
@@ -630,8 +608,8 @@
           return principals
In most instances ``authenticated_userid`` and ``effective_principals`` are
application-specific whereas ``unauthenticated_userid``, ``remember`` and
``forget`` are generic and focused on transport/serialization of data
application-specific, whereas ``unauthenticated_userid``, ``remember``, and
``forget`` are generic and focused on transport and serialization of data
between consecutive requests.
.. index::
@@ -642,12 +620,11 @@
Creating Your Own Authentication Policy
---------------------------------------
:app:`Pyramid` ships with a number of useful out-of-the-box
security policies (see :mod:`pyramid.authentication`).  However,
creating your own authentication policy is often necessary when you
want to control the "horizontal and vertical" of how your users
authenticate.  Doing so is a matter of creating an instance of something
that implements the following interface:
:app:`Pyramid` ships with a number of useful out-of-the-box security policies
(see :mod:`pyramid.authentication`).  However, creating your own authentication
policy is often necessary when you want to control the "horizontal and
vertical" of how your users authenticate.  Doing so is a matter of creating an
instance of something that implements the following interface:
.. code-block:: python
   :linenos:
@@ -717,21 +694,19 @@
--------------------------------------
An authorization policy is a policy that allows or denies access after a user
has been authenticated.  Most :app:`Pyramid` applications will use the
default :class:`pyramid.authorization.ACLAuthorizationPolicy`.
has been authenticated.  Most :app:`Pyramid` applications will use the default
:class:`pyramid.authorization.ACLAuthorizationPolicy`.
However, in some cases, it's useful to be able to use a different
authorization policy than the default
:class:`~pyramid.authorization.ACLAuthorizationPolicy`.  For example, it
might be desirable to construct an alternate authorization policy which
allows the application to use an authorization mechanism that does not
involve :term:`ACL` objects.
However, in some cases, it's useful to be able to use a different authorization
policy than the default :class:`~pyramid.authorization.ACLAuthorizationPolicy`.
For example, it might be desirable to construct an alternate authorization
policy which allows the application to use an authorization mechanism that does
not involve :term:`ACL` objects.
:app:`Pyramid` ships with only a single default authorization
policy, so you'll need to create your own if you'd like to use a
different one.  Creating and using your own authorization policy is a
matter of creating an instance of an object that implements the
following interface:
:app:`Pyramid` ships with only a single default authorization policy, so you'll
need to create your own if you'd like to use a different one.  Creating and
using your own authorization policy is a matter of creating an instance of an
object that implements the following interface:
.. code-block:: python
    :linenos:
@@ -782,4 +757,3 @@
a secret across two different subsystems might drop the security of signing to
zero. Keys should not be re-used across different contexts where an attacker
has the possibility of providing a chosen plaintext.
docs/narr/subrequest.rst
@@ -17,6 +17,7 @@
Here's an example application which uses a subrequest:
.. code-block:: python
  :linenos:
   from wsgiref.simple_server import make_server
   from pyramid.config import Configurator
@@ -41,16 +42,16 @@
       server = make_server('0.0.0.0', 8080, app)
       server.serve_forever()
When ``/view_one`` is visted in a browser, the text printed in the browser
pane will be ``This came from view_two``.  The ``view_one`` view used the
:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response
from another view (``view_two``) within the same application when it
executed.  It did so by constructing a new request that had a URL that it
knew would match the ``view_two`` view registration, and passed that new
request along to :meth:`pyramid.request.Request.invoke_subrequest`.  The
``view_two`` view callable was invoked, and it returned a response.  The
``view_one`` view callable then simply returned the response it obtained from
the ``view_two`` view callable.
When ``/view_one`` is visted in a browser, the text printed in the browser pane
will be ``This came from view_two``.  The ``view_one`` view used the
:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response from
another view (``view_two``) within the same application when it executed.  It
did so by constructing a new request that had a URL that it knew would match
the ``view_two`` view registration, and passed that new request along to
:meth:`pyramid.request.Request.invoke_subrequest`.  The ``view_two`` view
callable was invoked, and it returned a response.  The ``view_one`` view
callable then simply returned the response it obtained from the ``view_two``
view callable.
Note that it doesn't matter if the view callable invoked via a subrequest
actually returns a *literal* Response object.  Any view callable that uses a
@@ -60,6 +61,8 @@
object:
.. code-block:: python
  :linenos:
  :emphasize-lines: 11
   from wsgiref.simple_server import make_server
   from pyramid.config import Configurator
@@ -83,19 +86,19 @@
       server = make_server('0.0.0.0', 8080, app)
       server.serve_forever()
Even though the ``view_two`` view callable returned a string, it was invoked
in such a way that the ``string`` renderer associated with the view
registration that was found turned it into a "real" response object for
consumption by ``view_one``.
Even though the ``view_two`` view callable returned a string, it was invoked in
such a way that the ``string`` renderer associated with the view registration
that was found turned it into a "real" response object for consumption by
``view_one``.
Being able to unconditionally obtain a response object by invoking a view
callable indirectly is the main advantage to using
:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing
a view callable and executing it directly.  Note that there's not much
advantage to invoking a view using a subrequest if you *can* invoke a view
callable directly.  Subrequests are slower and are less convenient if you
actually do want just the literal information returned by a function that
happens to be a view callable.
:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing a
view callable and executing it directly.  Note that there's not much advantage
to invoking a view using a subrequest if you *can* invoke a view callable
directly.  Subrequests are slower and are less convenient if you actually do
want just the literal information returned by a function that happens to be a
view callable.
Note that, by default, if a view callable invoked by a subrequest raises an
exception, the exception will be raised to the caller of
@@ -103,6 +106,8 @@
:term:`exception view` configured:
.. code-block:: python
  :linenos:
  :emphasize-lines: 11-16
   from wsgiref.simple_server import make_server
   from pyramid.config import Configurator
@@ -136,15 +141,21 @@
``excview`` :term:`exception view` will *not* be executed.  Instead, the call
to :meth:`~pyramid.request.Request.invoke_subrequest` will cause a
:exc:`ValueError` exception to be raised and a response will never be
generated.  We can change this behavior; how to do so is described below in
our discussion of the ``use_tweens`` argument.
generated.  We can change this behavior; how to do so is described below in our
discussion of the ``use_tweens`` argument.
.. index::
   pair: subrequest; use_tweens
Subrequests with Tweens
-----------------------
The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two
arguments: a positional argument ``request`` that must be provided, and
``use_tweens`` keyword argument that is optional; it defaults to ``False``.
arguments: a required positional argument ``request``, and an optional keyword
argument ``use_tweens`` which defaults to ``False``.
The ``request`` object passed to the API must be an object that implements
the Pyramid request interface (such as a :class:`pyramid.request.Request`
The ``request`` object passed to the API must be an object that implements the
Pyramid request interface (such as a :class:`pyramid.request.Request`
instance).  If ``use_tweens`` is ``True``, the request will be sent to the
:term:`tween` in the tween stack closest to the request ingress.  If
``use_tweens`` is ``False``, the request will be sent to the main router
@@ -153,9 +164,9 @@
In the example above, the call to
:meth:`~pyramid.request.Request.invoke_subrequest` will always raise an
exception.  This is because it's using the default value for ``use_tweens``,
which is ``False``.  You can pass ``use_tweens=True`` instead to ensure that
it will convert an exception to a Response if an :term:`exception view` is
configured instead of raising the exception.  This is because exception views
which is ``False``.  Alternatively, you can pass ``use_tweens=True`` to ensure
that it will convert an exception to a Response if an :term:`exception view` is
configured, instead of raising the exception.  This is because exception views
are called by the exception view :term:`tween` as described in
:ref:`exception_views` when any view raises an exception.
@@ -164,6 +175,8 @@
:meth:`~pyramid.request.Request.invoke_subrequest`, like this:
.. code-block:: python
  :linenos:
  :emphasize-lines: 7
   from wsgiref.simple_server import make_server
   from pyramid.config import Configurator
@@ -199,71 +212,70 @@
exception view to generate a response is run, and therefore ``excview`` is
executed.
This is one of the major differences between specifying the
``use_tweens=True`` and ``use_tweens=False`` arguments to
This is one of the major differences between specifying the ``use_tweens=True``
and ``use_tweens=False`` arguments to
:meth:`~pyramid.request.Request.invoke_subrequest`.  ``use_tweens=True`` may
also imply invoking transaction commit/abort for the logic executed in the
subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug
HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other
also imply invoking a transaction commit or abort for the logic executed in the
subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug HTML
if you've got ``pyramid_debugtoolbar`` in the tween list, and other
tween-related side effects as defined by your particular tween list.
The :meth:`~pyramid.request.Request.invoke_subrequest` function also
unconditionally:
- manages the threadlocal stack so that
unconditionally does the following:
- It manages the threadlocal stack so that
  :func:`~pyramid.threadlocal.get_current_request` and
  :func:`~pyramid.threadlocal.get_current_registry` work during a request
  (they will return the subrequest instead of the original request)
  :func:`~pyramid.threadlocal.get_current_registry` work during a request (they
  will return the subrequest instead of the original request).
- Adds a ``registry`` attribute and a ``invoke_subrequest`` attribute (a
  callable) to the request object it's handed.
- It adds a ``registry`` attribute and an ``invoke_subrequest`` attribute (a
  callable) to the request object to which it is handed.
- sets request extensions (such as those added via
- It sets request extensions (such as those added via
  :meth:`~pyramid.config.Configurator.add_request_method` or
  :meth:`~pyramid.config.Configurator.set_request_property`) on the subrequest
  object passed as ``request``
  object passed as ``request``.
- causes a :class:`~pyramid.events.NewRequest` event to be sent at the
- It causes a :class:`~pyramid.events.NewRequest` event to be sent at the
  beginning of request processing.
- causes a :class:`~pyramid.events.ContextFound` event to be sent when a
- It causes a :class:`~pyramid.events.ContextFound` event to be sent when a
  context resource is found.
- Ensures that the user implied by the request passed has the necessary
  authorization to invoke view callable before calling it.
- It ensures that the user implied by the request passed in has the necessary
  authorization to invoke the view callable before calling it.
- Calls any :term:`response callback` functions defined within the subrequest's
  lifetime if a response is obtained from the Pyramid application.
- It calls any :term:`response callback` functions defined within the
  subrequest's lifetime if a response is obtained from the Pyramid application.
- causes a :class:`~pyramid.events.NewResponse` event to be sent if a response
  is obtained.
- It causes a :class:`~pyramid.events.NewResponse` event to be sent if a
  response is obtained.
- Calls any :term:`finished callback` functions defined within the subrequest's
  lifetime.
- It calls any :term:`finished callback` functions defined within the
  subrequest's lifetime.
The invocation of a subrequest has more or less exactly the same effect as
the invocation of a request received by the Pyramid router from a web client
The invocation of a subrequest has more or less exactly the same effect as the
invocation of a request received by the :app:`Pyramid` router from a web client
when ``use_tweens=True``.  When ``use_tweens=False``, the tweens are skipped
but all the other steps take place.
It's a poor idea to use the original ``request`` object as an argument to
:meth:`~pyramid.request.Request.invoke_subrequest`.  You should construct a
new request instead as demonstrated in the above example, using
:meth:`~pyramid.request.Request.invoke_subrequest`.  You should construct a new
request instead as demonstrated in the above example, using
:meth:`pyramid.request.Request.blank`.  Once you've constructed a request
object, you'll need to massage it to match the view callable you'd like
to be executed during the subrequest.  This can be done by adjusting the
object, you'll need to massage it to match the view callable that you'd like to
be executed during the subrequest.  This can be done by adjusting the
subrequest's URL, its headers, its request method, and other attributes.  The
documentation for :class:`pyramid.request.Request` exposes the methods you
should call and attributes you should set on the request you create to
massage it into something that will actually match the view you'd like to
call via a subrequest.
should call and attributes you should set on the request that you create, then
massage it into something that will actually match the view you'd like to call
via a subrequest.
We've demonstrated use of a subrequest from within a view callable, but you
can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from
within a tween or an event handler as well.  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.
We've demonstrated use of a subrequest from within a view callable, but you can
use the :meth:`~pyramid.request.Request.invoke_subrequest` API from within a
tween or an event handler as well.  Even though you can do it, it's usually a
poor idea to invoke :meth:`~pyramid.request.Request.invoke_subrequest` from
within a tween, because tweens already, by definition, have access to a
function that will cause a subrequest (they are passed a ``handle`` function).
It's fine to invoke :meth:`~pyramid.request.Request.invoke_subrequest` from
within an event handler, however.
docs/narr/tb_introspector.png

docs/narr/testing.rst
@@ -13,34 +13,32 @@
class instance.  The unit is also referred to as a "unit under test".
The goal of a single unit test is to test **only** some permutation of the
"unit under test".  If you write a unit test that aims to verify the result
of a particular codepath through a Python function, you need only be
concerned about testing the code that *lives in the function body itself*.
If the function accepts a parameter that represents a complex application
"domain object" (such as a resource, a database connection, or an SMTP
server), the argument provided to this function during a unit test *need not
be* and likely *should not be* a "real" implementation object.  For example,
although a particular function implementation may accept an argument that
represents an SMTP server object, and the function may call a method of this
object when the system is operating normally that would result in an email
being sent, a unit test of this codepath of the function does *not* need to
test that an email is actually sent.  It just needs to make sure that the
function calls the method of the object provided as an argument that *would*
send an email if the argument happened to be the "real" implementation of an
SMTP server object.
"unit under test".  If you write a unit test that aims to verify the result of
a particular codepath through a Python function, you need only be concerned
about testing the code that *lives in the function body itself*. If the
function accepts a parameter that represents a complex application "domain
object" (such as a resource, a database connection, or an SMTP server), the
argument provided to this function during a unit test *need not be* and likely
*should not be* a "real" implementation object.  For example, although a
particular function implementation may accept an argument that represents an
SMTP server object, and the function may call a method of this object when the
system is operating normally that would result in an email being sent, a unit
test of this codepath of the function does *not* need to test that an email is
actually sent.  It just needs to make sure that the function calls the method
of the object provided as an argument that *would* send an email if the
argument happened to be the "real" implementation of an SMTP server object.
An *integration test*, on the other hand, is a different form of testing in
which the interaction between two or more "units" is explicitly tested.
Integration tests verify that the components of your application work
together.  You *might* make sure that an email was actually sent in an
integration test.
Integration tests verify that the components of your application work together.
You *might* make sure that an email was actually sent in an integration test.
A *functional test* is a form of integration test in which the application is
run "literally".  You would *have to* make sure that an email was actually
sent in a functional test, because it tests your code end to end.
run "literally".  You would *have to* make sure that an email was actually sent
in a functional test, because it tests your code end to end.
It is often considered best practice to write each type of tests for any
given codebase.  Unit testing often provides the opportunity to obtain better
It is often considered best practice to write each type of tests for any given
codebase.  Unit testing often provides the opportunity to obtain better
"coverage": it's usually possible to supply a unit under test with arguments
and/or an environment which causes *all* of its potential codepaths to be
executed.  This is usually not as easy to do with a set of integration or
@@ -55,9 +53,9 @@
Into Python <http://www.diveintopython.net/unit_testing/index.html>`_ by Mark
Pilgrim.
:app:`Pyramid` provides a number of facilities that make unit, integration,
and functional tests easier to write.  The facilities become particularly
useful when your code calls into :app:`Pyramid` -related framework functions.
:app:`Pyramid` provides a number of facilities that make unit, integration, and
functional tests easier to write.  The facilities become particularly useful
when your code calls into :app:`Pyramid`-related framework functions.
.. index::
   single: test setup
@@ -67,42 +65,41 @@
.. _test_setup_and_teardown:
Test Set Up and Tear Down
--------------------------
-------------------------
:app:`Pyramid` uses a "global" (actually :term:`thread local`) data structure
to hold two items: the current :term:`request` and the current
:term:`application registry`.  These data structures are available via the
:func:`pyramid.threadlocal.get_current_request` and
:func:`pyramid.threadlocal.get_current_registry` functions, respectively.
See :ref:`threadlocals_chapter` for information about these functions and the
data structures they return.
:func:`pyramid.threadlocal.get_current_registry` functions, respectively. See
:ref:`threadlocals_chapter` for information about these functions and the data
structures they return.
If your code uses these ``get_current_*`` functions or calls :app:`Pyramid`
code which uses ``get_current_*`` functions, you will need to call
:func:`pyramid.testing.setUp` in your test setup and you will need to call
:func:`pyramid.testing.tearDown` in your test teardown.
:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread
local` stack, which makes the ``get_current_*`` functions work.  It returns a
:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread local`
stack, which makes the ``get_current_*`` functions work.  It returns a
:term:`Configurator` object which can be used to perform extra configuration
required by the code under test.  :func:`~pyramid.testing.tearDown` pops the
thread local stack.
Normally when a Configurator is used directly with the ``main`` block of
a Pyramid application, it defers performing any "real work" until its
``.commit`` method is called (often implicitly by the
:meth:`pyramid.config.Configurator.make_wsgi_app` method).  The
Configurator returned by :func:`~pyramid.testing.setUp` is an
*autocommitting* Configurator, however, which performs all actions
implied by methods called on it immediately.  This is more convenient
for unit-testing purposes than needing to call
:meth:`pyramid.config.Configurator.commit` in each test after adding
extra configuration statements.
Normally when a Configurator is used directly with the ``main`` block of a
Pyramid application, it defers performing any "real work" until its ``.commit``
method is called (often implicitly by the
:meth:`pyramid.config.Configurator.make_wsgi_app` method).  The Configurator
returned by :func:`~pyramid.testing.setUp` is an *autocommitting* Configurator,
however, which performs all actions implied by methods called on it
immediately.  This is more convenient for unit testing purposes than needing to
call :meth:`pyramid.config.Configurator.commit` in each test after adding extra
configuration statements.
The use of the :func:`~pyramid.testing.setUp` and
:func:`~pyramid.testing.tearDown` functions allows you to supply each unit
test method in a test case with an environment that has an isolated registry
and an isolated request for the duration of a single test.  Here's an example
of using this feature:
:func:`~pyramid.testing.tearDown` functions allows you to supply each unit test
method in a test case with an environment that has an isolated registry and an
isolated request for the duration of a single test.  Here's an example of using
this feature:
.. code-block:: python
   :linenos:
@@ -117,22 +114,21 @@
       def tearDown(self):
           testing.tearDown()
The above will make sure that
:func:`~pyramid.threadlocal.get_current_registry` called within a test
case method of ``MyTest`` will return the :term:`application registry`
associated with the ``config`` Configurator instance.  Each test case
method attached to ``MyTest`` will use an isolated registry.
The above will make sure that :func:`~pyramid.threadlocal.get_current_registry`
called within a test case method of ``MyTest`` will return the
:term:`application registry` associated with the ``config`` Configurator
instance.  Each test case method attached to ``MyTest`` will use an isolated
registry.
The :func:`~pyramid.testing.setUp` and :func:`~pyramid.testing.tearDown`
functions accepts various arguments that influence the environment of the
test.  See the :ref:`testing_module` API for information about the extra
arguments supported by these functions.
functions accept various arguments that influence the environment of the test.
See the :ref:`testing_module` API for information about the extra arguments
supported by these functions.
If you also want to make :func:`~pyramid.threadlocal.get_current_request`
return something other than ``None`` during the course of a single test, you
can pass a
:term:`request` object into the :func:`pyramid.testing.setUp` within the
``setUp`` method of your test:
can pass a :term:`request` object into the :func:`pyramid.testing.setUp` within
the ``setUp`` method of your test:
.. code-block:: python
   :linenos:
@@ -148,24 +144,23 @@
       def tearDown(self):
           testing.tearDown()
If you pass a :term:`request` object into :func:`pyramid.testing.setUp`
within your test case's ``setUp``, any test method attached to the
``MyTest`` test case that directly or indirectly calls
If you pass a :term:`request` object into :func:`pyramid.testing.setUp` within
your test case's ``setUp``, any test method attached to the ``MyTest`` test
case that directly or indirectly calls
:func:`~pyramid.threadlocal.get_current_request` will receive the request
object.  Otherwise, during testing,
:func:`~pyramid.threadlocal.get_current_request` will return ``None``.
We use a "dummy" request implementation supplied by
:class:`pyramid.testing.DummyRequest` because it's easier to construct
than a "real" :app:`Pyramid` request object.
:func:`~pyramid.threadlocal.get_current_request` will return ``None``. We use a
"dummy" request implementation supplied by
:class:`pyramid.testing.DummyRequest` because it's easier to construct than a
"real" :app:`Pyramid` request object.
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.
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:
@@ -193,8 +188,8 @@
about any of this, but you still want to write test code, just always call
:func:`pyramid.testing.setUp` in your test's ``setUp`` method and
:func:`pyramid.testing.tearDown` in your tests' ``tearDown`` method.  This
won't really hurt anything if the application you're testing does not call
any ``get_current*`` function.
won't really hurt anything if the application you're testing does not call any
``get_current*`` function.
.. index::
   single: pyramid.testing
@@ -225,15 +220,15 @@
.. note::
   This code implies that you have defined a renderer imperatively in a
   relevant :class:`pyramid.config.Configurator` instance,
   otherwise it would fail when run normally.
   relevant :class:`pyramid.config.Configurator` instance, otherwise it would
   fail when run normally.
Without doing anything special during a unit test, the call to
:meth:`~pyramid.request.Request.has_permission` in this view function will
always return a ``True`` value.  When a :app:`Pyramid` application starts
normally, it will populate a :term:`application registry` using
normally, it will populate an :term:`application registry` using
:term:`configuration declaration` calls made against a :term:`Configurator`.
But if this application registry is not created and populated (e.g. by
But if this application registry is not created and populated (e.g., by
initializing the configurator with an authorization policy), like when you
invoke application code via a unit test, :app:`Pyramid` API functions will tend
to either fail or return default results.  So how do you test the branch of the
@@ -283,10 +278,10 @@
be found when ``setup.py test`` is run.  It has two test methods.
The first test method, ``test_view_fn_forbidden`` tests the ``view_fn`` when
the authentication policy forbids the current user the ``edit`` permission.
Its third line registers a "dummy" "non-permissive" authorization policy
using the :meth:`~pyramid.config.Configurator.testing_securitypolicy` method,
which is a special helper method for unit testing.
the authentication policy forbids the current user the ``edit`` permission. Its
third line registers a "dummy" "non-permissive" authorization policy using the
:meth:`~pyramid.config.Configurator.testing_securitypolicy` method, which is a
special helper method for unit testing.
We then create a :class:`pyramid.testing.DummyRequest` object which simulates a
WebOb request object API.  A :class:`pyramid.testing.DummyRequest` is a request
@@ -300,25 +295,25 @@
The second test method, named ``test_view_fn_allowed``, tests the alternate
case, where the authentication policy allows access.  Notice that we pass
different values to
:meth:`~pyramid.config.Configurator.testing_securitypolicy` to obtain this
result.  We assert at the end of this that the view function returns a value.
different values to :meth:`~pyramid.config.Configurator.testing_securitypolicy`
to obtain this result.  We assert at the end of this that the view function
returns a value.
Note that the test calls the :func:`pyramid.testing.setUp` function in its
``setUp`` method and the :func:`pyramid.testing.tearDown` function in its
``tearDown`` method.  We assign the result of :func:`pyramid.testing.setUp`
as ``config`` on the unittest class.  This is a :term:`Configurator` object
and all methods of the configurator can be called as necessary within
tests. If you use any of the :class:`~pyramid.config.Configurator` APIs during
testing, be sure to use this pattern in your test case's ``setUp`` and
``tearDown``; these methods make sure you're using a "fresh"
:term:`application registry` per test run.
``tearDown`` method.  We assign the result of :func:`pyramid.testing.setUp` as
``config`` on the unittest class.  This is a :term:`Configurator` object and
all methods of the configurator can be called as necessary within tests. If you
use any of the :class:`~pyramid.config.Configurator` APIs during testing, be
sure to use this pattern in your test case's ``setUp`` and ``tearDown``; these
methods make sure you're using a "fresh" :term:`application registry` per test
run.
See the :ref:`testing_module` chapter for the entire :app:`Pyramid` -specific
See the :ref:`testing_module` chapter for the entire :app:`Pyramid`-specific
testing API.  This chapter describes APIs for registering a security policy,
registering resources at paths, registering event listeners, registering
views and view permissions, and classes representing "dummy" implementations
of a request and a resource.
registering resources at paths, registering event listeners, registering views
and view permissions, and classes representing "dummy" implementations of a
request and a resource.
.. seealso::
@@ -392,7 +387,7 @@
package, which provides APIs for invoking HTTP(S) requests to your application.
Regardless of which testing :term:`package` you use, ensure to add a
``tests_require`` dependency on that package to to your application's
``tests_require`` dependency on that package to your application's
``setup.py`` file:
   .. literalinclude:: MyProject/setup.py
@@ -400,7 +395,7 @@
      :emphasize-lines: 26-28,48
      :language: python
Assuming your :term:`package` is named ``myproject``, which contains a
Let us assume your :term:`package` is named ``myproject`` which contains a
``views`` module, which in turn contains a :term:`view` function ``my_view``
that returns a HTML body when the root URL is invoked:
@@ -408,8 +403,8 @@
      :linenos:
      :language: python
Then the following example functional test (shown below) demonstrates invoking
the :term:`view` shown above:
Then the following example functional test demonstrates invoking the above
:term:`view`:
   .. literalinclude:: MyProject/myproject/tests.py
      :linenos:
@@ -419,9 +414,9 @@
When this test is run, each test method creates a "real" :term:`WSGI`
application using the ``main`` function in your ``myproject.__init__`` module,
using :term:`WebTest` to wrap that WSGI application.  It assigns the result to
``self.testapp``.  In the test named ``test_root``. The ``TestApp``'s ``get``
``self.testapp``.  In the test named ``test_root``. The ``TestApp``'s ``GET``
method is used to invoke the root URL.  Finally, an assertion is made that the
returned HTML contains the text ``MyProject``.
See the :term:`WebTest` documentation for further information about the
methods available to a :class:`webtest.app.TestApp` instance.
See the :term:`WebTest` documentation for further information about the methods
available to a :class:`webtest.app.TestApp` instance.
docs/narr/traversal.rst
@@ -3,32 +3,30 @@
Traversal
=========
This chapter explains the technical details of how traversal works in
Pyramid.
This chapter explains the technical details of how traversal works in Pyramid.
For a quick example, see :doc:`hellotraversal`.
For more about *why* you might use traversal, see :doc:`muchadoabouttraversal`.
A :term:`traversal` uses the URL (Universal Resource Locator) to find a
:term:`resource` located in a :term:`resource tree`, which is a set of
nested dictionary-like objects.  Traversal is done by using each segment
of the path portion of the URL to navigate through the :term:`resource
tree`.  You might think of this as looking up files and directories in a
file system.  Traversal walks down the path until it finds a published
resource, analogous to a file system "directory" or "file".  The
resource found as the result of a traversal becomes the
:term:`context` of the :term:`request`.  Then, the :term:`view lookup`
subsystem is used to find some view code willing to "publish" this
:term:`resource` located in a :term:`resource tree`, which is a set of nested
dictionary-like objects.  Traversal is done by using each segment of the path
portion of the URL to navigate through the :term:`resource tree`.  You might
think of this as looking up files and directories in a file system.  Traversal
walks down the path until it finds a published resource, analogous to a file
system "directory" or "file".  The resource found as the result of a traversal
becomes the :term:`context` of the :term:`request`.  Then, the :term:`view
lookup` subsystem is used to find some view code willing to "publish" this
resource by generating a :term:`response`.
.. note::
  Using :term:`Traversal` to map a URL to code is optional.  If you're creating
  your first Pyramid application it probably makes more sense to use :term:`URL
  dispatch` to map URLs to code instead of traversal, as new Pyramid developers
  tend to find URL dispatch slightly easier to understand.  If you use URL
  dispatch, you needn't read this chapter.
  your first Pyramid application, it probably makes more sense to use
  :term:`URL dispatch` to map URLs to code instead of traversal, as new Pyramid
  developers tend to find URL dispatch slightly easier to understand.  If you
  use URL dispatch, you needn't read this chapter.
.. index::
   single: traversal details
@@ -36,33 +34,32 @@
Traversal Details
-----------------
:term:`Traversal` is dependent on information in a :term:`request`
object.  Every :term:`request` object contains URL path information in
the ``PATH_INFO`` portion of the :term:`WSGI` environment.  The
``PATH_INFO`` string is the portion of a request's URL following the
hostname and port number, but before any query string elements or
fragment element.  For example the ``PATH_INFO`` portion of the URL
``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``.
:term:`Traversal` is dependent on information in a :term:`request` object.
Every :term:`request` object contains URL path information in the ``PATH_INFO``
portion of the :term:`WSGI` environment.  The ``PATH_INFO`` string is the
portion of a request's URL following the hostname and port number, but before
any query string elements or fragment element.  For example the ``PATH_INFO``
portion of the URL ``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``.
Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of
path segments.  For example, the ``PATH_INFO`` string ``/a/b/c`` is
converted to the sequence ``['a', 'b', 'c']``.
Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of path
segments.  For example, the ``PATH_INFO`` string ``/a/b/c`` is converted to the
sequence ``['a', 'b', 'c']``.
This path sequence is then used to descend through the :term:`resource
tree`, looking up a resource for each path segment. Each lookup uses the
This path sequence is then used to descend through the :term:`resource tree`,
looking up a resource for each path segment. Each lookup uses the
``__getitem__`` method of a resource in the tree.
For example, if the path info sequence is ``['a', 'b', 'c']``:
- :term:`Traversal` starts by acquiring the :term:`root` resource of the
  application by calling the :term:`root factory`. The :term:`root factory`
  can be configured to return whatever object is appropriate as the
  traversal root of your application.
  application by calling the :term:`root factory`. The :term:`root factory` can
  be configured to return whatever object is appropriate as the traversal root
  of your application.
- Next, the first element (``'a'``) is popped from the path segment
  sequence and is used as a key to lookup the corresponding resource
  in the root. This invokes the root resource's ``__getitem__`` method
  using that value (``'a'``) as an argument.
- Next, the first element (``'a'``) is popped from the path segment sequence
  and is used as a key to lookup the corresponding resource in the root. This
  invokes the root resource's ``__getitem__`` method using that value (``'a'``)
  as an argument.
- If the root resource "contains" a resource with key ``'a'``, its
  ``__getitem__`` method will return it. The :term:`context` temporarily
@@ -72,29 +69,26 @@
  resource's ``__getitem__`` is called with that value (``'b'``) as an
  argument; we'll presume it succeeds.
- The "A" resource's ``__getitem__`` returns another resource, which
  we'll call "B".  The :term:`context` temporarily becomes the "B"
  resource.
- The "A" resource's ``__getitem__`` returns another resource, which we'll call
  "B".  The :term:`context` temporarily becomes the "B" resource.
Traversal continues until the path segment sequence is exhausted or a
path element cannot be resolved to a resource.  In either case, the
:term:`context` resource is the last object that the traversal
successfully resolved.  If any resource found during traversal lacks a
``__getitem__`` method, or if its ``__getitem__`` method raises a
:exc:`KeyError`, traversal ends immediately, and that resource becomes
the :term:`context`.
Traversal continues until the path segment sequence is exhausted or a path
element cannot be resolved to a resource.  In either case, the :term:`context`
resource is the last object that the traversal successfully resolved.  If any
resource found during traversal lacks a ``__getitem__`` method, or if its
``__getitem__`` method raises a :exc:`KeyError`, traversal ends immediately,
and that resource becomes the :term:`context`.
The results of a :term:`traversal` also include a :term:`view name`. If
traversal ends before the path segment sequence is exhausted, the
:term:`view name` is the *next* remaining path segment element. If the
:term:`traversal` expends all of the path segments, then the :term:`view
name` is the empty string (``''``).
traversal ends before the path segment sequence is exhausted, the :term:`view
name` is the *next* remaining path segment element. If the :term:`traversal`
expends all of the path segments, then the :term:`view name` is the empty
string (``''``).
The combination of the context resource and the :term:`view name` found
via traversal is used later in the same request by the :term:`view
lookup` subsystem to find a :term:`view callable`.  How :app:`Pyramid`
performs view lookup is explained within the :ref:`view_config_chapter`
chapter.
The combination of the context resource and the :term:`view name` found via
traversal is used later in the same request by the :term:`view lookup`
subsystem to find a :term:`view callable`.  How :app:`Pyramid` performs view
lookup is explained within the :ref:`view_config_chapter` chapter.
.. index::
   single: object tree
@@ -106,20 +100,20 @@
The Resource Tree
-----------------
The resource tree is a set of nested dictionary-like resource objects
that begins with a :term:`root` resource. In order to use
:term:`traversal` to resolve URLs to code, your application must supply
a :term:`resource tree` to :app:`Pyramid`.
The resource tree is a set of nested dictionary-like resource objects that
begins with a :term:`root` resource. In order to use :term:`traversal` to
resolve URLs to code, your application must supply a :term:`resource tree` to
:app:`Pyramid`.
In order to supply a root resource for an application the :app:`Pyramid`
:term:`Router` is configured with a callback known as a :term:`root
factory`.  The root factory is supplied by the application, at startup
time, as the ``root_factory`` argument to the :term:`Configurator`.
:term:`Router` is configured with a callback known as a :term:`root factory`.
The root factory is supplied by the application at startup time as the
``root_factory`` argument to the :term:`Configurator`.
The root factory is a Python callable that accepts a :term:`request`
object, and returns the root object of the :term:`resource tree`. A
function, or class is typically used as an application's root factory.
Here's an example of a simple root factory class:
The root factory is a Python callable that accepts a :term:`request` object,
and returns the root object of the :term:`resource tree`. A function or class
is typically used as an application's root factory. Here's an example of a
simple root factory class:
.. code-block:: python
   :linenos:
@@ -136,62 +130,60 @@
   config = Configurator(root_factory=Root)
The ``root_factory`` argument to the
:class:`~pyramid.config.Configurator` constructor registers this root
factory to be called to generate a root resource whenever a request
enters the application.  The root factory registered this way is also
known as the global root factory.  A root factory can alternately be
passed to the ``Configurator`` as a :term:`dotted Python name` which can
refer to a root factory defined in a different module.
The ``root_factory`` argument to the :class:`~pyramid.config.Configurator`
constructor registers this root factory to be called to generate a root
resource whenever a request enters the application.  The root factory
registered this way is also known as the global root factory.  A root factory
can alternatively be passed to the ``Configurator`` as a :term:`dotted Python
name` which can refer to a root factory defined in a different module.
If no :term:`root factory` is passed to the :app:`Pyramid`
:term:`Configurator` constructor, or if the ``root_factory`` value
specified is ``None``, a :term:`default root factory` is used.  The default
root factory always returns a resource that has no child resources; it
is effectively empty.
If no :term:`root factory` is passed to the :app:`Pyramid` :term:`Configurator`
constructor, or if the ``root_factory`` value specified is ``None``, a
:term:`default root factory` is used.  The default root factory always returns
a resource that has no child resources; it is effectively empty.
Usually a root factory for a traversal-based application will be more
complicated than the above ``Root`` class; in particular it may be associated
complicated than the above ``Root`` class.  In particular it may be associated
with a database connection or another persistence mechanism.  The above
``Root`` class is analogous to the default root factory present in Pyramid. The
default root factory is very simple and not very useful.
.. note::
   If the items contained within the resource tree are "persistent" (they
   have state that lasts longer than the execution of a single process), they
   become analogous to the concept of :term:`domain model` objects used by
   many other frameworks.
   If the items contained within the resource tree are "persistent" (they have
   state that lasts longer than the execution of a single process), they become
   analogous to the concept of :term:`domain model` objects used by many other
   frameworks.
The resource tree consists of *container* resources and *leaf* resources.
There is only one difference between a *container* resource and a *leaf*
resource: *container* resources possess a ``__getitem__`` method (making it
The resource tree consists of *container* resources and *leaf* resources. There
is only one difference between a *container* resource and a *leaf* resource:
*container* resources possess a ``__getitem__`` method (making it
"dictionary-like") while *leaf* resources do not.  The ``__getitem__`` method
was chosen as the signifying difference between the two types of resources
because the presence of this method is how Python itself typically determines
whether an object is "containerish" or not (dictionary objects are
"containerish").
Each container resource is presumed to be willing to return a child resource
or raise a ``KeyError`` based on a name passed to its ``__getitem__``.
Each container resource is presumed to be willing to return a child resource or
raise a ``KeyError`` based on a name passed to its ``__getitem__``.
Leaf-level instances must not have a ``__getitem__``.  If instances that
you'd like to be leaves already happen to have a ``__getitem__`` through some
Leaf-level instances must not have a ``__getitem__``.  If instances that you'd
like to be leaves already happen to have a ``__getitem__`` through some
historical inequity, you should subclass these resource types and cause their
``__getitem__`` methods to simply raise a ``KeyError``.  Or just disuse them
and think up another strategy.
Usually, the traversal root is a *container* resource, and as such it
contains other resources.  However, it doesn't *need* to be a container.
Your resource tree can be as shallow or as deep as you require.
Usually the traversal root is a *container* resource, and as such it contains
other resources.  However, it doesn't *need* to be a container. Your resource
tree can be as shallow or as deep as you require.
In general, the resource tree is traversed beginning at its root resource
using a sequence of path elements described by the ``PATH_INFO`` of the
current request; if there are path segments, the root resource's
``__getitem__`` is called with the next path segment, and it is expected to
return another resource.  The resulting resource's ``__getitem__`` is called
with the very next path segment, and it is expected to return another
resource.  This happens *ad infinitum* until all path segments are exhausted.
In general, the resource tree is traversed beginning at its root resource using
a sequence of path elements described by the ``PATH_INFO`` of the current
request.  If there are path segments, the root resource's ``__getitem__`` is
called with the next path segment, and it is expected to return another
resource.  The resulting resource's ``__getitem__`` is called with the very
next path segment, and it is expected to return another resource.  This happens
*ad infinitum* until all path segments are exhausted.
.. index::
   single: traversal algorithm
@@ -204,17 +196,17 @@
This section will attempt to explain the :app:`Pyramid` traversal algorithm.
We'll provide a description of the algorithm, a diagram of how the algorithm
works, and some example traversal scenarios that might help you understand
how the algorithm operates against a specific resource tree.
works, and some example traversal scenarios that might help you understand how
the algorithm operates against a specific resource tree.
We'll also talk a bit about :term:`view lookup`.  The
:ref:`view_config_chapter` chapter discusses :term:`view lookup` in
detail, and it is the canonical source for information about views.
Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that is
separated from traversal entirely.  However, we'll describe the
fundamental behavior of view lookup in the examples in the next few
sections to give you an idea of how traversal and view lookup cooperate,
because they are almost always used together.
:ref:`view_config_chapter` chapter discusses :term:`view lookup` in detail, and
it is the canonical source for information about views. Technically,
:term:`view lookup` is a :app:`Pyramid` subsystem that is separated from
traversal entirely.  However, we'll describe the fundamental behavior of view
lookup in the examples in the next few sections to give you an idea of how
traversal and view lookup cooperate, because they are almost always used
together.
.. index::
   single: view name
@@ -223,26 +215,24 @@
   single: root factory
   single: default view
A Description of The Traversal Algorithm
A Description of the Traversal Algorithm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a user requests a page from your traversal-powered application, the
system uses this algorithm to find a :term:`context` resource and a
:term:`view name`.
When a user requests a page from your traversal-powered application, the system
uses this algorithm to find a :term:`context` resource and a :term:`view name`.
#.  The request for the page is presented to the :app:`Pyramid`
    :term:`router` in terms of a standard :term:`WSGI` request, which is
    represented by a WSGI environment and a WSGI ``start_response`` callable.
#.  The request for the page is presented to the :app:`Pyramid` :term:`router`
    in terms of a standard :term:`WSGI` request, which is represented by a WSGI
    environment and a WSGI ``start_response`` callable.
#.  The router creates a :term:`request` object based on the WSGI
    environment.
#.  The router creates a :term:`request` object based on the WSGI environment.
#.  The :term:`root factory` is called with the :term:`request`.  It returns
    a :term:`root` resource.
#.  The :term:`root factory` is called with the :term:`request`.  It returns a
    :term:`root` resource.
#.  The router uses the WSGI environment's ``PATH_INFO`` information to
    determine the path segments to traverse.  The leading slash is stripped
    off ``PATH_INFO``, and the remaining path segments are split on the slash
    determine the path segments to traverse.  The leading slash is stripped off
    ``PATH_INFO``, and the remaining path segments are split on the slash
    character to form a traversal sequence.
    The traversal algorithm by default attempts to first URL-unquote and then
@@ -252,26 +242,26 @@
    Conversion from a URL-decoded string into Unicode is attempted using the
    UTF-8 encoding.  If any URL-unquoted path segment in ``PATH_INFO`` is not
    decodeable using the UTF-8 decoding, a :exc:`TypeError` is raised.  A
    segment will be fully URL-unquoted and UTF8-decoded before it is passed
    in to the ``__getitem__`` of any resource during traversal.
    segment will be fully URL-unquoted and UTF8-decoded before it is passed in
    to the ``__getitem__`` of any resource during traversal.
    Thus, a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
    Thus a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
    traversal sequence ``[u'a', u'b', u'c']``.
#.  :term:`Traversal` begins at the root resource returned by the root
    factory.  For the traversal sequence ``[u'a', u'b', u'c']``, the root
    resource's ``__getitem__`` is called with the name ``'a'``.  Traversal
    continues through the sequence.  In our example, if the root resource's
    ``__getitem__`` called with the name ``a`` returns a resource (aka
#.  :term:`Traversal` begins at the root resource returned by the root factory.
    For the traversal sequence ``[u'a', u'b', u'c']``, the root resource's
    ``__getitem__`` is called with the name ``'a'``.  Traversal continues
    through the sequence.  In our example, if the root resource's
    ``__getitem__`` called with the name ``a`` returns a resource (a.k.a.
    resource "A"), that resource's ``__getitem__`` is called with the name
    ``'b'``.  If resource "A" returns a resource "B" when asked for ``'b'``,
    resource B's ``__getitem__`` is then asked for the name ``'c'``, and may
    return resource "C".
#.  Traversal ends when a) the entire path is exhausted or b) when any
    resource raises a :exc:`KeyError` from its ``__getitem__`` or c) when any
#.  Traversal ends when either (a) the entire path is exhausted, (b) when any
    resource raises a :exc:`KeyError` from its ``__getitem__``, (c) when any
    non-final path element traversal does not have a ``__getitem__`` method
    (resulting in a :exc:`AttributeError`) or d) when any path element is
    (resulting in an :exc:`AttributeError`), or (d) when any path element is
    prefixed with the set of characters ``@@`` (indicating that the characters
    following the ``@@`` token should be treated as a :term:`view name`).
@@ -279,13 +269,13 @@
    resource found during traversal is deemed to be the :term:`context`.  If
    the path has been exhausted when traversal ends, the :term:`view name` is
    deemed to be the empty string (``''``).  However, if the path was *not*
    exhausted before traversal terminated, the first remaining path segment
    is treated as the view name.
    exhausted before traversal terminated, the first remaining path segment is
    treated as the view name.
#.  Any subsequent path elements after the :term:`view name` is found are
    deemed the :term:`subpath`.  The subpath is always a sequence of path
    segments that come from ``PATH_INFO`` that are "left over" after
    traversal has completed.
    segments that come from ``PATH_INFO`` that are "left over" after traversal
    has completed.
Once the :term:`context` resource, the :term:`view name`, and associated
attributes such as the :term:`subpath` are located, the job of
@@ -297,20 +287,19 @@
- You will often end up with a :term:`view name` that is the empty string as
  the result of a particular traversal.  This indicates that the view lookup
  machinery should look up the :term:`default view`.  The default view is a
  view that is registered with no name or a view which is registered with a
  name that equals the empty string.
  machinery should lookup the :term:`default view`.  The default view is a view
  that is registered with no name or a view which is registered with a name
  that equals the empty string.
- If any path segment element begins with the special characters ``@@``
  (think of them as goggles), the value of that segment minus the goggle
  characters is considered the :term:`view name` immediately and traversal
  stops there.  This allows you to address views that may have the same names
  as resource names in the tree unambiguously.
- If any path segment element begins with the special characters ``@@`` (think
  of them as goggles), the value of that segment minus the goggle characters is
  considered the :term:`view name` immediately and traversal stops there.  This
  allows you to address views that may have the same names as resource names in
  the tree unambiguously.
Finally, traversal is responsible for locating a :term:`virtual root`.  A
virtual root is used during "virtual hosting"; see the
:ref:`vhosting_chapter` chapter for information.  We won't speak more about
it in this chapter.
virtual root is used during "virtual hosting".  See the :ref:`vhosting_chapter`
chapter for information.  We won't speak more about it in this chapter.
.. image:: resourcetreetraverser.png
@@ -321,13 +310,13 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
No one can be expected to understand the traversal algorithm by analogy and
description alone, so let's examine some traversal scenarios that use
concrete URLs and resource tree compositions.
description alone, so let's examine some traversal scenarios that use concrete
URLs and resource tree compositions.
Let's pretend the user asks for
``http://example.com/foo/bar/baz/biz/buz.txt``. The request's ``PATH_INFO``
in that case is ``/foo/bar/baz/biz/buz.txt``.  Let's further pretend that
when this request comes in that we're traversing the following resource tree:
Let's pretend the user asks for ``http://example.com/foo/bar/baz/biz/buz.txt``.
The request's ``PATH_INFO`` in that case is ``/foo/bar/baz/biz/buz.txt``.
Let's further pretend that when this request comes in, we're traversing the
following resource tree:
.. code-block:: text
@@ -346,33 +335,32 @@
  finds.
- :term:`traversal` traverses "bar", and attempts to find "baz", which it does
  not find (the "bar" resource raises a :exc:`KeyError` when asked for
  "baz").
  not find (the "bar" resource raises a :exc:`KeyError` when asked for "baz").
The fact that it does not find "baz" at this point does not signify an error
condition.  It signifies that:
condition.  It signifies the following:
- the :term:`context` is the "bar" resource (the context is the last resource
- The :term:`context` is the "bar" resource (the context is the last resource
  found during traversal).
- the :term:`view name` is ``baz``
- The :term:`view name` is ``baz``.
- the :term:`subpath` is ``('biz', 'buz.txt')``
- The :term:`subpath` is ``('biz', 'buz.txt')``.
At this point, traversal has ended, and :term:`view lookup` begins.
Because it's the "context" resource, the view lookup machinery examines "bar"
to find out what "type" it is. Let's say it finds that the context is a
``Bar`` type (because "bar" happens to be an instance of the class ``Bar``).
Using the :term:`view name` (``baz``) and the type, view lookup asks the
to find out what "type" it is. Let's say it finds that the context is a ``Bar``
type (because "bar" happens to be an instance of the class ``Bar``). Using the
:term:`view name` (``baz``) and the type, view lookup asks the
:term:`application registry` this question:
- Please find me a :term:`view callable` registered using a :term:`view
  configuration` with the name "baz" that can be used for the class ``Bar``.
Let's say that view lookup finds no matching view type.  In this
circumstance, the :app:`Pyramid` :term:`router` returns the result of the
:term:`Not Found View` and the request ends.
Let's say that view lookup finds no matching view type.  In this circumstance,
the :app:`Pyramid` :term:`router` returns the result of the :term:`Not Found
View` and the request ends.
However, for this tree:
@@ -399,59 +387,58 @@
- :term:`traversal` traverses "baz", and attempts to find "biz", which it
  finds.
- :term:`traversal` traverses "biz", and attempts to find "buz.txt" which it
- :term:`traversal` traverses "biz", and attempts to find "buz.txt", which it
  does not find.
The fact that it does not find a resource related to "buz.txt" at this point
does not signify an error condition.  It signifies that:
does not signify an error condition.  It signifies the following:
- the :term:`context` is the "biz" resource (the context is the last resource
- The :term:`context` is the "biz" resource (the context is the last resource
  found during traversal).
- the :term:`view name` is "buz.txt"
- The :term:`view name` is "buz.txt".
- the :term:`subpath` is an empty sequence ( ``()`` ).
- The :term:`subpath` is an empty sequence ( ``()`` ).
At this point, traversal has ended, and :term:`view lookup` begins.
Because it's the "context" resource, the view lookup machinery examines the
"biz" resource to find out what "type" it is. Let's say it finds that the
resource is a ``Biz`` type (because "biz" is an instance of the Python class
``Biz``).  Using the :term:`view name` (``buz.txt``) and the type, view
lookup asks the :term:`application registry` this question:
``Biz``).  Using the :term:`view name` (``buz.txt``) and the type, view lookup
asks the :term:`application registry` this question:
- Please find me a :term:`view callable` registered with a :term:`view
  configuration` with the name ``buz.txt`` that can be used for class
  ``Biz``.
  configuration` with the name ``buz.txt`` that can be used for class ``Biz``.
Let's say that question is answered by the application registry; in such a
situation, the application registry returns a :term:`view callable`.  The
view callable is then called with the current :term:`WebOb` :term:`request`
as the sole argument: ``request``; it is expected to return a response.
Let's say that question is answered by the application registry.  In such a
situation, the application registry returns a :term:`view callable`.  The view
callable is then called with the current :term:`WebOb` :term:`request` as the
sole argument, ``request``.  It is expected to return a response.
.. sidebar:: The Example View Callables Accept Only a Request; How Do I Access the Context Resource?
.. sidebar:: The Example View Callables Accept Only a Request; How Do I Access
   the Context Resource?
   Most of the examples in this book assume that a view callable is typically
   passed only a :term:`request` object.  Sometimes your view callables need
   access to the :term:`context` resource, especially when you use
   :term:`traversal`.  You might use a supported alternate view callable
   Most of the examples in this documentation assume that a view callable is
   typically passed only a :term:`request` object.  Sometimes your view
   callables need access to the :term:`context` resource, especially when you
   use :term:`traversal`.  You might use a supported alternative view callable
   argument list in your view callables such as the ``(context, request)``
   calling convention described in
   :ref:`request_and_context_view_definitions`.  But you don't need to if you
   don't want to.  In view callables that accept only a request, the
   :term:`context` resource found by traversal is available as the
   ``context`` attribute of the request object, e.g. ``request.context``.
   The :term:`view name` is available as the ``view_name`` attribute of the
   request object, e.g. ``request.view_name``.  Other :app:`Pyramid`
   -specific request attributes are also available as described in
   :ref:`special_request_attributes`.
   calling convention described in :ref:`request_and_context_view_definitions`.
   But you don't need to if you don't want to.  In view callables that accept
   only a request, the :term:`context` resource found by traversal is available
   as the ``context`` attribute of the request object, e.g.,
   ``request.context``. The :term:`view name` is available as the ``view_name``
   attribute of the request object, e.g., ``request.view_name``.  Other
   :app:`Pyramid`-specific request attributes are also available as described
   in :ref:`special_request_attributes`.
.. index::
   single: resource interfaces
.. _using_resource_interfaces:
Using Resource Interfaces In View Configuration
Using Resource Interfaces in View Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of registering your views with a ``context`` that names a Python
@@ -460,18 +447,17 @@
arbitrarily to any resource object.  View lookup treats context interfaces
specially, and therefore the identity of a resource can be divorced from that
of the class which implements it.  As a result, associating a view with an
interface can provide more flexibility for sharing a single view between two
or more different implementations of a resource type.  For example, if two
resource objects of different Python class types share the same interface,
you can use the same view configuration to specify both of them as a
``context``.
interface can provide more flexibility for sharing a single view between two or
more different implementations of a resource type.  For example, if two
resource objects of different Python class types share the same interface, you
can use the same view configuration to specify both of them as a ``context``.
In order to make use of interfaces in your application during view dispatch,
you must create an interface and mark up your resource classes or instances
with interface declarations that refer to this interface.
To attach an interface to a resource *class*, you define the interface and
use the :func:`zope.interface.implementer` class decorator to associate the
To attach an interface to a resource *class*, you define the interface and use
the :func:`zope.interface.implementer` class decorator to associate the
interface with the class.
.. code-block:: python
@@ -488,9 +474,9 @@
       pass
To attach an interface to a resource *instance*, you define the interface and
use the :func:`zope.interface.alsoProvides` function to associate the
interface with the instance.  This function mutates the instance in such a
way that the interface is attached to it.
use the :func:`zope.interface.alsoProvides` function to associate the interface
with the instance.  This function mutates the instance in such a way that the
interface is attached to it.
.. code-block:: python
   :linenos:
@@ -509,13 +495,13 @@
       alsoProvides(hello, IHello)
       return hello
Regardless of how you associate an interface, with a resource instance, or a
resource class, the resulting code to associate that interface with a view
Regardless of how you associate an interface—with either a resource instance
or a resource class—the resulting code to associate that interface with a view
callable is the same.  Assuming the above code that defines an ``IHello``
interface lives in the root of your application, and its module is named
"resources.py", the interface declaration below will associate the
``mypackage.views.hello_world`` view with resources that implement, or
provide, this interface.
``mypackage.views.hello_world`` view with resources that implement, or provide,
this interface.
.. code-block:: python
   :linenos:
@@ -525,20 +511,18 @@
   config.add_view('mypackage.views.hello_world', name='hello.html',
                   context='mypackage.resources.IHello')
Any time a resource that is determined to be the :term:`context` provides
this interface, and a view named ``hello.html`` is looked up against it as
per the URL, the ``mypackage.views.hello_world`` view callable will be
invoked.
Any time a resource that is determined to be the :term:`context` provides this
interface, and a view named ``hello.html`` is looked up against it as per the
URL, the ``mypackage.views.hello_world`` view callable will be invoked.
Note, in cases where a view is registered against a resource class, and a
view is also registered against an interface that the resource class
implements, an ambiguity arises. Views registered for the resource class take
precedence over any views registered for any interface the resource class
implements. Thus, if one view configuration names a ``context`` of both the
class type of a resource, and another view configuration names a ``context``
of interface implemented by the resource's class, and both view
configurations are otherwise identical, the view registered for the context's
class will "win".
Note, in cases where a view is registered against a resource class, and a view
is also registered against an interface that the resource class implements, an
ambiguity arises. Views registered for the resource class take precedence over
any views registered for any interface the resource class implements. Thus, if
one view configuration names a ``context`` of both the class type of a
resource, and another view configuration names a ``context`` of interface
implemented by the resource's class, and both view configurations are otherwise
identical, the view registered for the context's class will "win".
For more information about defining resources with interfaces for use within
view configuration, see :ref:`resources_which_implement_interfaces`.
@@ -558,4 +542,3 @@
The :meth:`pyramid.request.Request.resource_url` method generates a URL when
given a resource retrieved from a resource tree.
docs/quick_tour.rst
@@ -818,14 +818,14 @@
language. SQLAlchemy uses "models" for this mapping. The scaffold
generated a sample model:
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/models/mymodel.py
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/models.py
    :start-after: Start Sphinx Include
    :end-before: End Sphinx Include
View code, which mediates the logic between web requests and the rest
of the system, can then easily get at the data thanks to SQLAlchemy:
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/views/default.py
.. literalinclude:: quick_tour/sqla_demo/sqla_demo/views.py
    :start-after: Start Sphinx Include
    :end-before: End Sphinx Include
docs/quick_tour/sqla_demo/development.ini
@@ -27,7 +27,7 @@
[server:main]
use = egg:waitress#main
host = 127.0.0.1
host = 0.0.0.0
port = 6543
###
@@ -68,4 +68,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
docs/quick_tour/sqla_demo/production.ini
@@ -59,4 +59,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
docs/quick_tour/sqla_demo/setup.py
@@ -3,18 +3,15 @@
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.txt')) as f:
    README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
    CHANGES = f.read()
README = open(os.path.join(here, 'README.txt')).read()
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
requires = [
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'zope.sqlalchemy',
    'waitress',
    ]
docs/quick_tour/sqla_demo/sqla_demo.sqlite
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/__init__.py
@@ -1,12 +1,19 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
    DBSession,
    Base,
    )
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_jinja2')
    config.include('.models.meta')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
docs/quick_tour/sqla_demo/sqla_demo/models.py
New file
@@ -0,0 +1,29 @@
from sqlalchemy import (
    Column,
    Integer,
    Text,
    )
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
    )
from zope.sqlalchemy import ZopeTransactionExtension
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
# Start Sphinx Include
class MyModel(Base):
    __tablename__ = 'models'
    id = Column(Integer, primary_key=True)
    name = Column(Text, unique=True)
    value = Column(Integer)
    def __init__(self, name, value):
        self.name = name
        self.value = value
    # End Sphinx Include
docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/models/meta.py
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/models/mymodel.py
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/scripts/initializedb.py
@@ -2,44 +2,36 @@
import sys
import transaction
from sqlalchemy import engine_from_config
from pyramid.paster import (
    get_appsettings,
    setup_logging,
    )
from pyramid.scripts.common import parse_vars
from ..models.meta import (
from ..models import (
    DBSession,
    MyModel,
    Base,
    get_session,
    get_engine,
    get_dbmaker,
    )
from ..models.mymodel import MyModel
def usage(argv):
    cmd = os.path.basename(argv[0])
    print('usage: %s <config_uri> [var=value]\n'
    print('usage: %s <config_uri>\n'
          '(example: "%s development.ini")' % (cmd, cmd))
    sys.exit(1)
def main(argv=sys.argv):
    if len(argv) < 2:
    if len(argv) != 2:
        usage(argv)
    config_uri = argv[1]
    options = parse_vars(argv[2:])
    setup_logging(config_uri)
    settings = get_appsettings(config_uri, options=options)
    engine = get_engine(settings)
    dbmaker = get_dbmaker(engine)
    dbsession = get_session(transaction.manager, dbmaker)
    settings = get_appsettings(config_uri)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)
    with transaction.manager:
        model = MyModel(name='one', value=1)
        dbsession.add(model)
        DBSession.add(model)
docs/quick_tour/sqla_demo/sqla_demo/static/favicon.ico
docs/quick_tour/sqla_demo/sqla_demo/static/footerbg.png
docs/quick_tour/sqla_demo/sqla_demo/static/headerbg.png
docs/quick_tour/sqla_demo/sqla_demo/static/ie6.css
New file
@@ -0,0 +1,8 @@
* html img,
* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
);}
#wrap{display:table;height:100%}
docs/quick_tour/sqla_demo/sqla_demo/static/middlebg.png
docs/quick_tour/sqla_demo/sqla_demo/static/pylons.css
New file
@@ -0,0 +1,372 @@
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
{
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  font-size: 100%; /* 16px */
  vertical-align: baseline;
  background: transparent;
}
body
{
  line-height: 1;
}
ol, ul
{
  list-style: none;
}
blockquote, q
{
  quotes: none;
}
blockquote:before, blockquote:after, q:before, q:after
{
  content: '';
  content: none;
}
:focus
{
  outline: 0;
}
ins
{
  text-decoration: none;
}
del
{
  text-decoration: line-through;
}
table
{
  border-collapse: collapse;
  border-spacing: 0;
}
sub
{
  vertical-align: sub;
  font-size: smaller;
  line-height: normal;
}
sup
{
  vertical-align: super;
  font-size: smaller;
  line-height: normal;
}
ul, menu, dir
{
  display: block;
  list-style-type: disc;
  margin: 1em 0;
  padding-left: 40px;
}
ol
{
  display: block;
  list-style-type: decimal-leading-zero;
  margin: 1em 0;
  padding-left: 40px;
}
li
{
  display: list-item;
}
ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
{
  margin-top: 0;
  margin-bottom: 0;
}
ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
{
  list-style-type: circle;
}
ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
{
  list-style-type: square;
}
.hidden
{
  display: none;
}
p
{
  line-height: 1.5em;
}
h1
{
  font-size: 1.75em;
  line-height: 1.7em;
  font-family: helvetica, verdana;
}
h2
{
  font-size: 1.5em;
  line-height: 1.7em;
  font-family: helvetica, verdana;
}
h3
{
  font-size: 1.25em;
  line-height: 1.7em;
  font-family: helvetica, verdana;
}
h4
{
  font-size: 1em;
  line-height: 1.7em;
  font-family: helvetica, verdana;
}
html, body
{
  width: 100%;
  height: 100%;
}
body
{
  margin: 0;
  padding: 0;
  background-color: #fff;
  position: relative;
  font: 16px/24px NobileRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
}
a
{
  color: #1b61d6;
  text-decoration: none;
}
a:hover
{
  color: #e88f00;
  text-decoration: underline;
}
body h1, body h2, body h3, body h4, body h5, body h6
{
  font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
  font-weight: 400;
  color: #373839;
  font-style: normal;
}
#wrap
{
  min-height: 100%;
}
#header, #footer
{
  width: 100%;
  color: #fff;
  height: 40px;
  position: absolute;
  text-align: center;
  line-height: 40px;
  overflow: hidden;
  font-size: 12px;
  vertical-align: middle;
}
#header
{
  background: #000;
  top: 0;
  font-size: 14px;
}
#footer
{
  bottom: 0;
  background: #000 url(footerbg.png) repeat-x 0 top;
  position: relative;
  margin-top: -40px;
  clear: both;
}
.header, .footer
{
  width: 750px;
  margin-right: auto;
  margin-left: auto;
}
.wrapper
{
  width: 100%;
}
#top, #top-small, #bottom
{
  width: 100%;
}
#top
{
  color: #000;
  height: 230px;
  background: #fff url(headerbg.png) repeat-x 0 top;
  position: relative;
}
#top-small
{
  color: #000;
  height: 60px;
  background: #fff url(headerbg.png) repeat-x 0 top;
  position: relative;
}
#bottom
{
  color: #222;
  background-color: #fff;
}
.top, .top-small, .middle, .bottom
{
  width: 750px;
  margin-right: auto;
  margin-left: auto;
}
.top
{
  padding-top: 40px;
}
.top-small
{
  padding-top: 10px;
}
#middle
{
  width: 100%;
  height: 100px;
  background: url(middlebg.png) repeat-x;
  border-top: 2px solid #fff;
  border-bottom: 2px solid #b2b2b2;
}
.app-welcome
{
  margin-top: 25px;
}
.app-name
{
  color: #000;
  font-weight: 700;
}
.bottom
{
  padding-top: 50px;
}
#left
{
  width: 350px;
  float: left;
  padding-right: 25px;
}
#right
{
  width: 350px;
  float: right;
  padding-left: 25px;
}
.align-left
{
  text-align: left;
}
.align-right
{
  text-align: right;
}
.align-center
{
  text-align: center;
}
ul.links
{
  margin: 0;
  padding: 0;
}
ul.links li
{
  list-style-type: none;
  font-size: 14px;
}
form
{
  border-style: none;
}
fieldset
{
  border-style: none;
}
input
{
  color: #222;
  border: 1px solid #ccc;
  font-family: sans-serif;
  font-size: 12px;
  line-height: 16px;
}
input[type=text], input[type=password]
{
  width: 205px;
}
input[type=submit]
{
  background-color: #ddd;
  font-weight: 700;
}
/*Opera Fix*/
body:before
{
  content: "";
  height: 100%;
  float: left;
  width: 0;
  margin-top: -32767px;
}
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-16x16.png
Binary files differ
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid-small.png
docs/quick_tour/sqla_demo/sqla_demo/static/pyramid.png

docs/quick_tour/sqla_demo/sqla_demo/static/theme.css
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/static/theme.min.css
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/static/transparent.gif
docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.jinja2
File was deleted
docs/quick_tour/sqla_demo/sqla_demo/templates/mytemplate.pt
New file
@@ -0,0 +1,76 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>The Pyramid Web Framework</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon" href="${request.static_url('sqla_demo:static/favicon.ico')}" />
  <link rel="stylesheet" href="${request.static_url('sqla_demo:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
  <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
  <!--[if lte IE 6]>
  <link rel="stylesheet" href="${request.static_url('sqla_demo:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top">
      <div class="top align-center">
        <div><img src="${request.static_url('sqla_demo:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-center">
        <p class="app-welcome">
          Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
          the Pyramid web framework.
        </p>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <div id="left" class="align-right">
          <h2>Search documentation</h2>
          <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/search.html">
                <input type="text" id="q" name="q" value="" />
                <input type="submit" id="x" value="Go" />
            </form>
        </div>
        <div id="right" class="align-left">
          <h2>Pyramid links</h2>
          <ul class="links">
            <li>
              <a href="http://pylonsproject.org">Pylons Website</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#narrative-documentation">Narrative Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#reference-material">API Documentation</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#tutorials">Tutorials</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#detailed-change-history">Change History</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#sample-applications">Sample Applications</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/#support-and-development">Support and Development</a>
            </li>
            <li>
              <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
            </li>
            </ul>
        </div>
      </div>
    </div>
  </div>
  <div id="footer">
    <div class="footer">&copy; Copyright 2008-2012, Agendaless Consulting.</div>
  </div>
</body>
</html>
docs/quick_tour/sqla_demo/sqla_demo/tests.py
@@ -3,63 +3,31 @@
from pyramid import testing
def dummy_request(dbsession):
    return testing.DummyRequest(dbsession=dbsession)
from .models import DBSession
class BaseTest(unittest.TestCase):
class TestMyView(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp(settings={
            'sqlalchemy.url': 'sqlite:///:memory:'
        })
        self.config.include('.models.meta')
        settings = self.config.get_settings()
        from .models.meta import (
            get_session,
            get_engine,
            get_dbmaker,
        self.config = testing.setUp()
        from sqlalchemy import create_engine
        engine = create_engine('sqlite://')
        from .models import (
            Base,
            MyModel,
            )
        self.engine = get_engine(settings)
        dbmaker = get_dbmaker(self.engine)
        self.session = get_session(transaction.manager, dbmaker)
    def init_database(self):
        from .models.meta import Base
        Base.metadata.create_all(self.engine)
        DBSession.configure(bind=engine)
        Base.metadata.create_all(engine)
        with transaction.manager:
            model = MyModel(name='one', value=55)
            DBSession.add(model)
    def tearDown(self):
        from .models.meta import Base
        DBSession.remove()
        testing.tearDown()
        transaction.abort()
        Base.metadata.create_all(self.engine)
class TestMyViewSuccessCondition(BaseTest):
    def setUp(self):
        super(TestMyViewSuccessCondition, self).setUp()
        self.init_database()
        from .models.mymodel import MyModel
        model = MyModel(name='one', value=55)
        self.session.add(model)
    def test_passing_view(self):
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
    def test_it(self):
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        self.assertEqual(info['one'].name, 'one')
        self.assertEqual(info['project'], 'sqla_demo')
class TestMyViewFailureCondition(BaseTest):
    def test_failing_view(self):
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        self.assertEqual(info.status_int, 500)
docs/quick_tour/sqla_demo/sqla_demo/views.py
File was renamed from docs/quick_tour/sqla_demo/sqla_demo/views/default.py
@@ -3,27 +3,28 @@
from sqlalchemy.exc import DBAPIError
from ..models.mymodel import MyModel
from .models import (
    DBSession,
    MyModel,
    )
@view_config(route_name='home', renderer='../templates/mytemplate.jinja2')
@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
    try:
        query = request.dbsession.query(MyModel)
        # Start Sphinx Include
        one = query.filter(MyModel.name == 'one').first()
        one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
        # End Sphinx Include
    except DBAPIError:
        return Response(db_err_msg, content_type='text/plain', status_int=500)
        return Response(conn_err_msg, content_type='text/plain', status_int=500)
    return {'one': one, 'project': 'sqla_demo'}
db_err_msg = """\
conn_err_msg = """\
Pyramid is having a problem using your SQL database.  The problem
might be caused by one of the following things:
1.  You may need to run the "initialize_sqla_demo_db" script
    to initialize your database tables.  Check your virtual
    to initialize your database tables.  Check your virtual
    environment's "bin" directory for this script and try to run it.
2.  Your database server may not be running.  Check that the
@@ -33,3 +34,4 @@
After you fix the problem, please restart the Pyramid application to
try it again.
"""
docs/quick_tour/sqla_demo/sqla_demo/views/__init__.py
docs/tutorials/wiki2/basiclayout.rst
@@ -12,12 +12,12 @@
A directory on disk can be turned into a Python :term:`package` by containing
an ``__init__.py`` file.  Even if empty, this marks a directory as a Python
package.  We use ``__init__.py`` both as a marker, indicating the directory in
which it's contained is a package, and to contain application configuration
package.  We use ``__init__.py`` both as a marker, indicating the directory
in which it's contained is a package, and to contain application configuration
code.
Open ``tutorial/tutorial/__init__.py``.  It should already contain the
following:
Open ``tutorial/tutorial/__init__.py``.  It should already contain
the following:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :linenos:
@@ -43,37 +43,58 @@
above is executed.  It accepts some settings and returns a :term:`WSGI`
application.  (See :ref:`startup_chapter` for more about ``pserve``.)
The main function first creates a :term:`SQLAlchemy` database engine using
:func:`sqlalchemy.engine_from_config` from the ``sqlalchemy.`` prefixed
settings in the ``development.ini`` file's ``[app:main]`` section.
This will be a URI (something like ``sqlite://``):
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 13
      :language: py
``main`` then initializes our SQLAlchemy session object, passing it the
engine:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 14
      :language: py
``main`` subsequently initializes our SQLAlchemy declarative ``Base`` object,
assigning the engine we created to the ``bind`` attribute of it's
``metadata`` object.  This allows table definitions done imperatively
(instead of declaratively, via a class statement) to work.  We won't use any
such tables in our application, but if you add one later, long after you've
forgotten about this tutorial, you won't be left scratching your head when it
doesn't work.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 15
      :language: py
The next step of ``main`` is to construct a :term:`Configurator` object:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 7
      :lines: 16
      :language: py
``settings`` is passed to the Configurator as a keyword argument with the
dictionary values passed as the ``**settings`` argument.  This will be a
dictionary of settings parsed from the ``.ini`` file, which contains
deployment-related values such as ``pyramid.reload_templates``,
``sqlalchemy.url``, and so on.
``db_string``, etc.
Next include :term:`Jinja2` templating bindings so that we can use renderers
with the ``.jinja2`` extension within our project.
Next, include :term:`Chameleon` templating bindings so that we can use
renderers with the ``.pt`` extension within our project.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 8
      :language: py
Next include the module ``meta`` from the package ``models`` using a dotted
Python path.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 9
      :lines: 17
      :language: py
``main`` now calls :meth:`pyramid.config.Configurator.add_static_view` with
two arguments: ``static`` (the name), and ``static`` (the path):
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 10
      :lines: 18
      :language: py
This registers a static resource view which will match any URL that starts
@@ -91,11 +112,11 @@
used when the URL is ``/``:
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 11
      :lines: 19
      :language: py
Since this route has a ``pattern`` equaling ``/``, it is the route that will
be matched when the URL ``/`` is visited, e.g., ``http://localhost:6543/``.
Since this route has a ``pattern`` equaling ``/`` it is the route that will
be matched when the URL ``/`` is visited, e.g. ``http://localhost:6543/``.
``main`` next calls the ``scan`` method of the configurator
(:meth:`pyramid.config.Configurator.scan`), which will recursively scan our
@@ -105,10 +126,10 @@
application URLs to be mapped to some code.
   .. literalinclude:: src/basiclayout/tutorial/__init__.py
      :lines: 12
      :lines: 20
      :language: py
Finally ``main`` is finished configuring things, so it uses the
Finally, ``main`` is finished configuring things, so it uses the
:meth:`pyramid.config.Configurator.make_wsgi_app` method to return a
:term:`WSGI` application:
docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -27,7 +27,7 @@
[server:main]
use = egg:waitress#main
host = 127.0.0.1
host = 0.0.0.0
port = 6543
###
@@ -68,4 +68,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
docs/tutorials/wiki2/src/basiclayout/production.ini
@@ -59,4 +59,4 @@
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -1,12 +1,20 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
    DBSession,
    Base,
    )
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_jinja2')
    config.include('.models.meta')
    config.include('pyramid_chameleon')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
pyramid/config/routes.py
@@ -268,7 +268,7 @@
          Pass a key/value pair here to use a third-party predicate
          registered via
          :meth:`pyramid.config.Configurator.add_view_predicate`.  More than
          :meth:`pyramid.config.Configurator.add_route_predicate`.  More than
          one key/value pair can be used at the same time.  See
          :ref:`view_and_route_predicates` for more information about
          third-party predicates.
@@ -421,14 +421,14 @@
    @action_method
    def add_route_predicate(self, name, factory, weighs_more_than=None,
                           weighs_less_than=None):
                            weighs_less_than=None):
        """ Adds a route predicate factory.  The view predicate can later be
        named as a keyword argument to
        :meth:`pyramid.config.Configurator.add_route`.
        ``name`` should be the name of the predicate.  It must be a valid
        Python identifier (it will be used as a keyword argument to
        ``add_view``).
        ``add_route``).
        ``factory`` should be a :term:`predicate factory` or :term:`dotted
        Python name` which refers to a predicate factory.
pyramid/scaffolds/alchemy/+package+/__init__.py
@@ -1,12 +1,20 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from .models import (
    DBSession,
    Base,
    )
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_jinja2')
    config.include('.models.meta')
    config.include('pyramid_chameleon')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
pyramid/scaffolds/alchemy/+package+/models.py
New file
@@ -0,0 +1,27 @@
from sqlalchemy import (
    Column,
    Index,
    Integer,
    Text,
    )
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import (
    scoped_session,
    sessionmaker,
    )
from zope.sqlalchemy import ZopeTransactionExtension
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
class MyModel(Base):
    __tablename__ = 'models'
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    value = Column(Integer)
Index('my_index', MyModel.name, unique=True, mysql_length=255)
pyramid/scaffolds/alchemy/+package+/models/__init__.py
File was deleted
pyramid/scaffolds/alchemy/+package+/models/meta.py
File was deleted
pyramid/scaffolds/alchemy/+package+/models/mymodel.py
File was deleted
pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py
@@ -2,6 +2,8 @@
import sys
import transaction
from sqlalchemy import engine_from_config
from pyramid.paster import (
    get_appsettings,
    setup_logging,
@@ -9,13 +11,11 @@
from pyramid.scripts.common import parse_vars
from ..models.meta import (
from ..models import (
    DBSession,
    MyModel,
    Base,
    get_session,
    get_engine,
    get_dbmaker,
    )
from ..models.mymodel import MyModel
def usage(argv):
@@ -32,14 +32,9 @@
    options = parse_vars(argv[2:])
    setup_logging(config_uri)
    settings = get_appsettings(config_uri, options=options)
    engine = get_engine(settings)
    dbmaker = get_dbmaker(engine)
    dbsession = get_session(transaction.manager, dbmaker)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.create_all(engine)
    with transaction.manager:
        model = MyModel(name='one', value=1)
        dbsession.add(model)
        DBSession.add(model)
pyramid/scaffolds/alchemy/+package+/templates/mytemplate.jinja2_tmpl
File was deleted
pyramid/scaffolds/alchemy/+package+/templates/mytemplate.pt_tmpl
File was renamed from pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl
@@ -1,12 +1,12 @@
<!DOCTYPE html>
<html lang="\{\{request.locale_name\}\}">
<html lang="${request.locale_name}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="\{\{request.static_url('{{package}}:static/pyramid-16x16.png')\}\}">
    <link rel="shortcut icon" href="${request.static_url('{{package}}:static/pyramid-16x16.png')}">
    <title>Alchemy Scaffold for The Pyramid Web Framework</title>
@@ -14,7 +14,7 @@
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this scaffold -->
    <link href="\{\{request.static_url('{{package}}:static/theme.css')\}\}" rel="stylesheet">
    <link href="${request.static_url('{{package}}:static/theme.css')}" rel="stylesheet">
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
@@ -29,12 +29,13 @@
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="\{\{request.static_url('{{package}}:static/pyramid.png')\}\}" alt="pyramid web framework">
            <img class="logo img-responsive" src="${request.static_url('{{package}}:static/pyramid.png')}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            {% block content %}
                <p>No content</p>
            {% endblock content %}
            <div class="content">
              <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
              <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework {{pyramid_version}}</span>.</p>
            </div>
          </div>
        </div>
        <div class="row">
pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
@@ -3,63 +3,53 @@
from pyramid import testing
def dummy_request(dbsession):
    return testing.DummyRequest(dbsession=dbsession)
from .models import DBSession
class BaseTest(unittest.TestCase):
class TestMyViewSuccessCondition(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp(settings={
            'sqlalchemy.url': 'sqlite:///:memory:'
        })
        self.config.include('.models.meta')
        settings = self.config.get_settings()
        from .models.meta import (
            get_session,
            get_engine,
            get_dbmaker,
        self.config = testing.setUp()
        from sqlalchemy import create_engine
        engine = create_engine('sqlite://')
        from .models import (
            Base,
            MyModel,
            )
        self.engine = get_engine(settings)
        dbmaker = get_dbmaker(self.engine)
        self.session = get_session(transaction.manager, dbmaker)
    def init_database(self):
        from .models.meta import Base
        Base.metadata.create_all(self.engine)
        DBSession.configure(bind=engine)
        Base.metadata.create_all(engine)
        with transaction.manager:
            model = MyModel(name='one', value=55)
            DBSession.add(model)
    def tearDown(self):
        from .models.meta import Base
        DBSession.remove()
        testing.tearDown()
        transaction.abort()
        Base.metadata.create_all(self.engine)
class TestMyViewSuccessCondition(BaseTest):
    def setUp(self):
        super(TestMyViewSuccessCondition, self).setUp()
        self.init_database()
        from .models.mymodel import MyModel
        model = MyModel(name='one', value=55)
        self.session.add(model)
    def test_passing_view(self):
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        self.assertEqual(info['one'].name, 'one')
        self.assertEqual(info['project'], '{{project}}')
class TestMyViewFailureCondition(BaseTest):
class TestMyViewFailureCondition(unittest.TestCase):
    def setUp(self):
        self.config = testing.setUp()
        from sqlalchemy import create_engine
        engine = create_engine('sqlite://')
        from .models import (
            Base,
            MyModel,
            )
        DBSession.configure(bind=engine)
    def tearDown(self):
        DBSession.remove()
        testing.tearDown()
    def test_failing_view(self):
        from .views.default import my_view
        info = my_view(dummy_request(self.session))
        self.assertEqual(info.status_int, 500)
        from .views import my_view
        request = testing.DummyRequest()
        info = my_view(request)
        self.assertEqual(info.status_int, 500)
pyramid/scaffolds/alchemy/+package+/views.py_tmpl
File was renamed from pyramid/scaffolds/alchemy/+package+/views/default.py_tmpl
@@ -3,20 +3,22 @@
from sqlalchemy.exc import DBAPIError
from ..models.mymodel import MyModel
from .models import (
    DBSession,
    MyModel,
    )
@view_config(route_name='home', renderer='../templates/mytemplate.jinja2')
@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
    try:
        query = request.dbsession.query(MyModel)
        one = query.filter(MyModel.name == 'one').first()
        one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
    except DBAPIError:
        return Response(db_err_msg, content_type='text/plain', status_int=500)
        return Response(conn_err_msg, content_type='text/plain', status_int=500)
    return {'one': one, 'project': '{{project}}'}
db_err_msg = """\
conn_err_msg = """\
Pyramid is having a problem using your SQL database.  The problem
might be caused by one of the following things:
@@ -31,3 +33,4 @@
After you fix the problem, please restart the Pyramid application to
try it again.
"""
pyramid/scaffolds/alchemy/+package+/views/__init__.py
pyramid/scaffolds/alchemy/setup.py_tmpl
@@ -10,7 +10,7 @@
requires = [
    'pyramid',
    'pyramid_jinja2',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'SQLAlchemy',
pyramid/scaffolds/copydir.py
@@ -106,9 +106,8 @@
        elif use_pkg_resources:
            content = pkg_resources.resource_string(source[0], full)
        else:
            f = open(full, 'rb')
            content = f.read()
            f.close()
            with open(full, 'rb') as f:
                content = f.read()
        if sub_file:
            try:
                content = substitute_content(
@@ -121,9 +120,8 @@
                continue  # pragma: no cover
        already_exists = os.path.exists(dest_full)
        if already_exists:
            f = open(dest_full, 'rb')
            old_content = f.read()
            f.close()
            with open(dest_full, 'rb') as f:
                old_content = f.read()
            if old_content == content:
                if verbosity:
                    out('%s%s already exists (same content)' %
@@ -144,9 +142,8 @@
                '%sCopying %s to %s' % (pad, os.path.basename(full),
                                        dest_full))
        if not simulate:
            f = open(dest_full, 'wb')
            f.write(content)
            f.close()
            with open(dest_full, 'wb') as f:
                f.write(content)
def should_skip_file(name):
    """
pyramid/scripts/pserve.py
@@ -243,7 +243,7 @@
            self._warn_daemon_deprecated()
            return self.show_status()
        if cmd == 'restart' or cmd == 'stop':
        if cmd in ('restart', 'stop'):
            self._warn_daemon_deprecated()
            result = self.stop_daemon()
            if result:
pyramid/scripts/pshell.py
@@ -12,11 +12,20 @@
from pyramid.paster import setup_logging
from pyramid.settings import aslist
from pyramid.scripts.common import parse_vars
def main(argv=sys.argv, quiet=False):
    command = PShellCommand(argv, quiet)
    return command.run()
def python_shell_runner(env, help, interact=interact):
    cprt = 'Type "help" for more information.'
    banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt)
    banner += '\n\n' + help + '\n'
    interact(banner, local=env)
class PShellCommand(object):
@@ -43,7 +52,14 @@
        )
    parser.add_option('-p', '--python-shell',
                      action='store', type='string', dest='python_shell',
                      default='', help='ipython | bpython | python')
                      default='',
                      help=('Select the shell to use. A list of possible '
                            'shells is available using the --list-shells '
                            'option.'))
    parser.add_option('-l', '--list-shells',
                      dest='list',
                      action='store_true',
                      help='List all available shells.')
    parser.add_option('--setup',
                      dest='setup',
                      help=("A callable that will be passed the environment "
@@ -52,9 +68,11 @@
                            "[pshell] ini section."))
    ConfigParser = configparser.ConfigParser # testing
    default_runner = python_shell_runner # testing
    loaded_objects = {}
    object_help = {}
    preferred_shells = []
    setup = None
    pystartup = os.environ.get('PYTHONSTARTUP')
@@ -64,6 +82,7 @@
    def pshell_file_config(self, filename):
        config = self.ConfigParser()
        config.optionxform = str
        config.read(filename)
        try:
            items = config.items('pshell')
@@ -77,6 +96,8 @@
        for k, v in items:
            if k == 'setup':
                self.setup = v
            elif k == 'default_shell':
                self.preferred_shells = [x.lower() for x in aslist(v)]
            else:
                self.loaded_objects[k] = resolver.maybe_resolve(v)
                self.object_help[k] = v
@@ -86,6 +107,8 @@
            print(msg)
    def run(self, shell=None):
        if self.options.list:
            return self.show_shells()
        if not self.args:
            self.out('Requires a config file argument')
            return 2
@@ -169,71 +192,64 @@
        finally:
            self.closer()
    def make_shell(self):
        shells = {}
    def show_shells(self):
        shells = self.find_all_shells()
        sorted_names = sorted(shells.keys(), key=lambda x: x.lower())
        for ep in self.pkg_resources.iter_entry_points('pyramid.pshell'):
        self.out('Available shells:')
        for name in sorted_names:
            self.out('  %s' % (name,))
        return 0
    def find_all_shells(self):
        pkg_resources = self.pkg_resources
        shells = {}
        for ep in pkg_resources.iter_entry_points('pyramid.pshell_runner'):
            name = ep.name
            shell_module = ep.load()
            shells[name] = shell_module
            shell_factory = ep.load()
            shells[name] = shell_factory
        return shells
    def make_shell(self):
        shells = self.find_all_shells()
        shell = None
        user_shell = self.options.python_shell.lower()
        if not user_shell:
            sorted_shells = sorted(shells.items(), key=lambda x: x[0])
            for name, factory in sorted_shells:
                shell = factory()
            preferred_shells = self.preferred_shells
            if not preferred_shells:
                # by default prioritize all shells above python
                preferred_shells = [k for k in shells.keys() if k != 'python']
            max_weight = len(preferred_shells)
            def order(x):
                # invert weight to reverse sort the list
                # (closer to the front is higher priority)
                try:
                    return preferred_shells.index(x[0].lower()) - max_weight
                except ValueError:
                    return 1
            sorted_shells = sorted(shells.items(), key=order)
                if shell is not None:
                    break
            if len(sorted_shells) > 0:
                shell = sorted_shells[0][1]
        else:
            factory = shells.get(user_shell)
            runner = shells.get(user_shell)
            if factory is not None:
                shell = factory()
            else:
            if runner is not None:
                shell = runner
            if shell is None:
                raise ValueError(
                    'could not find a shell named "%s"' % user_shell
                )
        if shell is None:
            shell = self.make_default_shell()
            # should never happen, but just incase entry points are borked
            shell = self.default_runner
        return shell
    def make_default_shell(self, interact=interact):
        def shell(env, help):
            cprt = 'Type "help" for more information.'
            banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt)
            banner += '\n\n' + help + '\n'
            interact(banner, local=env)
        return shell
    @classmethod
    def make_bpython_shell(cls, BPShell=None):
        if BPShell is None: # pragma: no cover
            try:
                from bpython import embed
                BPShell = embed
            except ImportError:
                return None
        def shell(env, help):
            BPShell(locals_=env, banner=help + '\n')
        return shell
    @classmethod
    def make_ipython_shell(cls, IPShellFactory=None):
        if IPShellFactory is None: # pragma: no cover
            try:
                from IPython.terminal.embed import (
                    InteractiveShellEmbed)
                IPShellFactory = InteractiveShellEmbed
            except ImportError:
                return None
        def shell(env, help):
            IPShell = IPShellFactory(banner2=help + '\n', user_ns=env)
            IPShell()
        return shell
pyramid/tests/test_authentication.py
@@ -1233,7 +1233,6 @@
                       'cd7a2fa4910000000auserid!')
        result = self._callFUT('secret', ticket, '2001:db8::1', 'sha256')
        self.assertEqual(result, (10, 'userid', [''], ''))
        pass
class TestSessionAuthenticationPolicy(unittest.TestCase):
    def _getTargetClass(self):
pyramid/tests/test_router.py
@@ -1284,7 +1284,7 @@
    def __call__(self, context, request):
        self.context = context
        self.request = request
        if not self.raise_exception is None:
        if self.raise_exception is not None:
            raise self.raise_exception
        return self.response
pyramid/tests/test_scripts/dummy.py
@@ -21,33 +21,17 @@
class DummyShell(object):
    env = {}
    help = ''
    called = False
    def __call__(self, env, help):
        self.env = env
        self.help = help
        self.called = True
class DummyInteractor:
    def __call__(self, banner, local):
        self.banner = banner
        self.local = local
class DummyBPythonShell:
    def __call__(self, locals_, banner):
        self.locals_ = locals_
        self.banner = banner
class DummyIPShell(object):
    IP = Dummy()
    IP.BANNER = 'foo'
    def __call__(self):
        self.called = True
class DummyIPShellFactory(object):
    def __call__(self, **kw):
        self.kw = kw
        self.shell = DummyIPShell()
        return self.shell
class DummyApp:
    def __init__(self):
pyramid/tests/test_scripts/test_pshell.py
@@ -26,6 +26,7 @@
            self.options = Options()
            self.options.python_shell = ''
            self.options.setup = None
            self.options.list = None
            cmd.options = self.options
        # default to None to prevent side-effects from running tests in
@@ -36,43 +37,12 @@
    def _makeEntryPoints(self, command, shells):
        command.pkg_resources = dummy.DummyPkgResources(shells)
    def test_make_default_shell(self):
        command = self._makeOne()
        interact = dummy.DummyInteractor()
        shell = command.make_default_shell(interact)
        shell({'foo': 'bar'}, 'a help message')
        self.assertEqual(interact.local, {'foo': 'bar'})
        self.assertTrue('a help message' in interact.banner)
    def test_make_bpython_shell(self):
        command = self._makeOne()
        bpython = dummy.DummyBPythonShell()
        shell = command.make_bpython_shell(bpython)
        shell({'foo': 'bar'}, 'a help message')
        self.assertEqual(bpython.locals_, {'foo': 'bar'})
        self.assertTrue('a help message' in bpython.banner)
    def test_make_ipython_v1_1_shell(self):
        command = self._makeOne()
        ipshell_factory = dummy.DummyIPShellFactory()
        shell = command.make_ipython_shell(ipshell_factory)
        shell({'foo': 'bar'}, 'a help message')
        self.assertEqual(ipshell_factory.kw['user_ns'], {'foo': 'bar'})
        self.assertTrue('a help message' in ipshell_factory.kw['banner2'])
        self.assertTrue(ipshell_factory.shell.called)
    def test_command_loads_default_shell(self):
        command = self._makeOne()
        shell = dummy.DummyShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: None,
                'bpython': lambda: None,
            }
        )
        self._makeEntryPoints(command, {})
        command.make_default_shell = lambda: shell
        command.default_runner = shell
        command.run()
        self.assertTrue(self.config_factory.parser)
        self.assertEqual(self.config_factory.parser.filename,
@@ -87,7 +57,7 @@
        self.assertTrue(self.bootstrap.closer.called)
        self.assertTrue(shell.help)
    def test_command_loads_default_shell_with_unknown_shell(self):
    def test_command_errors_with_unknown_shell(self):
        command = self._makeOne()
        out_calls = []
@@ -97,17 +67,10 @@
        command.out = out
        shell = dummy.DummyShell()
        bad_shell = dummy.DummyShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: bad_shell,
                'bpython': lambda: bad_shell,
            }
        )
        self._makeEntryPoints(command, {})
        command.make_default_shell = lambda: shell
        command.default_runner = shell
        command.options.python_shell = 'unknown_python_shell'
        result = command.run()
        self.assertEqual(result, 1)
@@ -120,14 +83,15 @@
        self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
        self.assertTrue(self.bootstrap.closer.called)
    def test_command_loads_ipython_v1_1(self):
    def test_command_loads_ipython(self):
        command = self._makeOne()
        shell = dummy.DummyShell()
        bad_shell = dummy.DummyShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: shell,
                'bpython': lambda: bad_shell,
                'ipython': shell,
                'bpython': bad_shell,
            }
        )
@@ -147,33 +111,6 @@
        self.assertTrue(self.bootstrap.closer.called)
        self.assertTrue(shell.help)
    def test_command_loads_bpython_shell(self):
        command = self._makeOne()
        shell = dummy.DummyBPythonShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: None,
                'bpython': lambda: shell,
            }
        )
        command.options.python_shell = 'bpython'
        command.run()
        self.assertTrue(self.config_factory.parser)
        self.assertEqual(self.config_factory.parser.filename,
                         '/foo/bar/myapp.ini')
        self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
        self.assertEqual(shell.locals_, {
            'app':self.bootstrap.app, 'root':self.bootstrap.root,
            'registry':self.bootstrap.registry,
            'request':self.bootstrap.request,
            'root_factory':self.bootstrap.root_factory,
        })
        self.assertTrue(self.bootstrap.closer.called)
        self.assertTrue(shell.banner)
    def test_shell_entry_points(self):
        command = self._makeOne()
        dshell = dummy.DummyShell()
@@ -181,48 +118,37 @@
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: dshell,
                'bpython': lambda: dshell,
                'ipython': dshell,
                'bpython': dshell,
            }
        )
        command.make_default_shell = lambda: None
        command.default_runner = None
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
    def test_shell_ordering(self):
    def test_shell_override(self):
        command = self._makeOne()
        ipshell = dummy.DummyShell()
        bpshell = dummy.DummyShell()
        dshell = dummy.DummyShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: None,
                'bpython': lambda: None,
            }
        )
        self._makeEntryPoints(command, {})
        command.make_default_shell = lambda: dshell
        command.default_runner = dshell
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
        command.options.python_shell = 'ipython'
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
        command.options.python_shell = 'bpython'
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
        self.assertRaises(ValueError, command.make_shell)
        self._makeEntryPoints(
            command,
            {
                'ipython': lambda: ipshell,
                'bpython': lambda: bpshell,
                'python': lambda: dshell,
                'ipython': ipshell,
                'bpython': bpshell,
                'python': dshell,
            }
        )
@@ -238,10 +164,40 @@
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
    def test_shell_ordering(self):
        command = self._makeOne()
        ipshell = dummy.DummyShell()
        bpshell = dummy.DummyShell()
        dshell = dummy.DummyShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': ipshell,
                'bpython': bpshell,
                'python': dshell,
            }
        )
        command.default_runner = dshell
        command.preferred_shells = ['ipython', 'bpython']
        shell = command.make_shell()
        self.assertEqual(shell, ipshell)
        command.preferred_shells = ['bpython', 'python']
        shell = command.make_shell()
        self.assertEqual(shell, bpshell)
        command.preferred_shells = ['python', 'ipython']
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
    def test_command_loads_custom_items(self):
        command = self._makeOne()
        model = dummy.Dummy()
        self.config_factory.items = [('m', model)]
        user = dummy.Dummy()
        self.config_factory.items = [('m', model), ('User', user)]
        shell = dummy.DummyShell()
        command.run(shell)
        self.assertTrue(self.config_factory.parser)
@@ -254,6 +210,7 @@
            'request':self.bootstrap.request,
            'root_factory':self.bootstrap.root_factory,
            'm':model,
            'User': user,
        })
        self.assertTrue(self.bootstrap.closer.called)
        self.assertTrue(shell.help)
@@ -281,6 +238,26 @@
        })
        self.assertTrue(self.bootstrap.closer.called)
        self.assertTrue(shell.help)
    def test_command_default_shell_option(self):
        command = self._makeOne()
        ipshell = dummy.DummyShell()
        dshell = dummy.DummyShell()
        self._makeEntryPoints(
            command,
            {
                'ipython': ipshell,
                'python': dshell,
            }
        )
        self.config_factory.items = [
            ('default_shell', 'bpython python\nipython')]
        command.run()
        self.assertTrue(self.config_factory.parser)
        self.assertEqual(self.config_factory.parser.filename,
                         '/foo/bar/myapp.ini')
        self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp')
        self.assertTrue(dshell.called)
    def test_command_loads_check_variable_override_order(self):
        command = self._makeOne()
@@ -369,6 +346,46 @@
        self.assertTrue(self.bootstrap.closer.called)
        self.assertTrue(shell.help)
    def test_list_shells(self):
        command = self._makeOne()
        dshell = dummy.DummyShell()
        out_calls = []
        def out(msg):
            out_calls.append(msg)
        command.out = out
        self._makeEntryPoints(
            command,
            {
                'ipython': dshell,
                'python': dshell,
            }
        )
        command.options.list = True
        result = command.run()
        self.assertEqual(result, 0)
        self.assertEqual(out_calls, [
            'Available shells:',
            '  ipython',
            '  python',
        ])
class Test_python_shell_runner(unittest.TestCase):
    def _callFUT(self, env, help, interact):
        from pyramid.scripts.pshell import python_shell_runner
        return python_shell_runner(env, help, interact=interact)
    def test_it(self):
        interact = dummy.DummyInteractor()
        self._callFUT({'foo': 'bar'}, 'a help message', interact)
        self.assertEqual(interact.local, {'foo': 'bar'})
        self.assertTrue('a help message' in interact.banner)
class Test_main(unittest.TestCase):
    def _callFUT(self, argv):
        from pyramid.scripts.pshell import main
@@ -377,4 +394,3 @@
    def test_it(self):
        result = self._callFUT(['pshell'])
        self.assertEqual(result, 2)
pyramid/util.py
@@ -30,7 +30,7 @@
class DottedNameResolver(_DottedNameResolver):
    def __init__(self, package=None): # default to package = None for bw compat
        return _DottedNameResolver.__init__(self, package)
        _DottedNameResolver.__init__(self, package)
_marker = object()
setup.py
@@ -111,9 +111,8 @@
        starter=pyramid.scaffolds:StarterProjectTemplate
        zodb=pyramid.scaffolds:ZODBProjectTemplate
        alchemy=pyramid.scaffolds:AlchemyProjectTemplate
        [pyramid.pshell]
        ipython=pyramid.scripts.pshell:PShellCommand.make_ipython_shell
        bpython=pyramid.scripts.pshell:PShellCommand.make_bpython_shell
        [pyramid.pshell_runner]
        python=pyramid.scripts.pshell:python_shell_runner
        [console_scripts]
        pcreate = pyramid.scripts.pcreate:main
        pserve = pyramid.scripts.pserve:main