Michael Merickel
2017-06-18 75c30dfe18b26ca04efae2acbe35052fa0d93ed6
Merge branch 'master' into pr/3034
1 files added
148 files modified
2550 ■■■■ changed files
CHANGES.txt 80 ●●●● patch | view | raw | blame | history
CONTRIBUTORS.txt 8 ●●●●● patch | view | raw | blame | history
README.rst 10 ●●●●● patch | view | raw | blame | history
RELEASING.txt 20 ●●●●● patch | view | raw | blame | history
contributing.md 2 ●●● patch | view | raw | blame | history
docs/api/security.rst 24 ●●●●● patch | view | raw | blame | history
docs/conf.py 2 ●●● patch | view | raw | blame | history
docs/glossary.rst 33 ●●●●● patch | view | raw | blame | history
docs/index.rst 6 ●●●●● patch | view | raw | blame | history
docs/narr/advanced-features.rst 330 ●●●●● patch | view | raw | blame | history
docs/narr/install.rst 4 ●●● patch | view | raw | blame | history
docs/narr/introduction.rst 956 ●●●● patch | view | raw | blame | history
docs/narr/myproject/development.ini 2 ●●● patch | view | raw | blame | history
docs/narr/myproject/myproject/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/narr/myproject/setup.py 1 ●●●● patch | view | raw | blame | history
docs/narr/project.rst 8 ●●●● patch | view | raw | blame | history
docs/narr/startup.rst 12 ●●●● patch | view | raw | blame | history
docs/narr/testing.rst 12 ●●●●● patch | view | raw | blame | history
docs/quick_tour.rst 28 ●●●●● patch | view | raw | blame | history
docs/quick_tour/logging/development.ini 2 ●●● patch | view | raw | blame | history
docs/quick_tour/logging/hello_world/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/quick_tour/logging/setup.py 1 ●●●● patch | view | raw | blame | history
docs/quick_tour/package/development.ini 2 ●●● patch | view | raw | blame | history
docs/quick_tour/package/hello_world/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/quick_tour/package/setup.py 1 ●●●● patch | view | raw | blame | history
docs/quick_tour/sessions/development.ini 2 ●●● patch | view | raw | blame | history
docs/quick_tour/sessions/hello_world/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/quick_tour/sessions/setup.py 1 ●●●● 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 6 ●●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/cookiecutters.rst 2 ●●● patch | view | raw | blame | history
docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/quick_tutorial/cookiecutters/development.ini 2 ●●● patch | view | raw | blame | history
docs/quick_tutorial/unit_testing.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/modwsgi/index.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/authorization.rst 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/basiclayout.rst 12 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/definingviews.rst 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/installation.rst 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/setup.py 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/tutorial/__init__.py 3 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/setup.py 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py 3 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/installation/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/installation/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/installation/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/installation/setup.py 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/installation/tutorial/__init__.py 3 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/setup.py 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/tutorial/__init__.py 3 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/setup.py 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/tutorial/__init__.py 3 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/tutorial/templates/login.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/tests/tutorial/templates/view.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/setup.py 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/__init__.py 3 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/templates/edit.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki/src/views/tutorial/templates/view.pt 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/authentication.rst 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/installation.rst 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authentication/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authentication/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authentication/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authentication/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/README.txt 2 ●●● 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/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/installation/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/installation/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/installation/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/installation/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 10 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/tests/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/tests/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/tests/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/tests/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2 8 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/README.txt 2 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/development.ini 4 ●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/production.ini 2 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/setup.py 6 ●●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/tutorial/models/__init__.py 4 ●●●● patch | view | raw | blame | history
docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 8 ●●●● patch | view | raw | blame | history
docs/whatsnew-1.9.rst 28 ●●●●● patch | view | raw | blame | history
pyramid/authentication.py 10 ●●●●● patch | view | raw | blame | history
pyramid/config/util.py 17 ●●●● patch | view | raw | blame | history
pyramid/encode.py 45 ●●●●● patch | view | raw | blame | history
pyramid/interfaces.py 8 ●●●●● patch | view | raw | blame | history
pyramid/router.py 43 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl 1 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl 10 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/alchemy/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl 10 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/starter/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/scaffolds/zodb/+package+/__init__.py 2 ●●●●● patch | view | raw | blame | history
pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl 10 ●●●● patch | view | raw | blame | history
pyramid/scaffolds/zodb/development.ini_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/security.py 114 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_config/test_util.py 10 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_encode.py 11 ●●●● patch | view | raw | blame | history
pyramid/tests/test_router.py 27 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_scaffolds/fixture_scaffold/+package+/templates/mytemplate.pt_tmpl 2 ●●● patch | view | raw | blame | history
pyramid/tests/test_security.py 28 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_view.py 46 ●●●●● patch | view | raw | blame | history
pyramid/threadlocal.py 2 ●●● patch | view | raw | blame | history
pyramid/view.py 67 ●●●●● patch | view | raw | blame | history
setup.py 2 ●●● patch | view | raw | blame | history
CHANGES.txt
@@ -1,3 +1,61 @@
unreleased
==========
- Add an informative error message when unknown predicates are supplied. The
  new message suggests alternatives based on the list of known predicates.
  See https://github.com/Pylons/pyramid/pull/3054
- Added integrity attributes for JavaScripts in cookiecutters, scaffolds, and
  resulting source files in tutorials.
  See https://github.com/Pylons/pyramid/issues/2548
- Update RELEASING.txt for updating cookiecutters. Change cookiecutter URLs to
  use shortcut.
  See https://github.com/Pylons/pyramid/issues/3042
- Ensure the correct threadlocals are pushed during view execution when
  invoked from ``request.invoke_exception_view``.
  See https://github.com/Pylons/pyramid/pull/3060
- Fix a bug in which ``pyramid.security.ALL_PERMISSIONS`` failed to return
  a valid iterator in its ``__iter__`` implementation.
  See https://github.com/Pylons/pyramid/pull/3074
- Normalize the permission results to a proper class hierarchy.
  ``pyramid.security.ACLAllowed`` is now a subclass of
  ``pyramid.security.Allowed`` and ``pyramid.security.ACLDenied`` is now a
  subclass of ``pyramid.security.Denied``.
  See https://github.com/Pylons/pyramid/pull/3084
- Add a ``quote_via`` argument to ``pyramid.encode.urlencode`` to follow
  the stdlib's version and enable custom quoting functions.
  See https://github.com/Pylons/pyramid/pull/3088
1.9a2 (2017-05-09)
==================
Backward Incompatibilities
--------------------------
- ``request.exception`` and ``request.exc_info`` will only be set if the
  response was generated by the EXCVIEW tween. This is to avoid any confusion
  where a response was generated elsewhere in the pipeline and not in
  direct relation to the original exception. If anyone upstream wants to
  catch and render responses for exceptions they should set
  ``request.exception`` and ``request.exc_info`` themselves to indicate
  the exception that was squashed when generating the response.
  Similar behavior occurs with ``request.invoke_exception_view`` in which
  the exception properties are set to reflect the exception if a response
  is successfully generated by the method.
  This is a very minor incompatibility. Most tweens right now would give
  priority to the raised exception and ignore ``request.exception``. This
  change just improves and clarifies that bookkeeping by trying to be
  more clear about the relationship between the response and its squashed
  exception. See https://github.com/Pylons/pyramid/pull/3029 and
  https://github.com/Pylons/pyramid/pull/3031
1.9a1 (2017-05-01)
==================
@@ -113,28 +171,6 @@
  See https://github.com/Pylons/pyramid/pull/2854 and
  https://github.com/Pylons/pyramid/pull/3019
Backward Incompatibilities
--------------------------
- ``request.exception`` and ``request.exc_info`` will only be set if the
  response was generated by the EXCVIEW tween. This is to avoid any confusion
  where a response was generated elsewhere in the pipeline and not in
  direct relation to the original exception. If anyone upstream wants to
  catch and render responses for exceptions they should set
  ``request.exception`` and ``request.exc_info`` themselves to indicate
  the exception that was squashed when generating the response.
  Similar behavior occurs with ``request.invoke_exception_view`` in which
  the exception properties are set to reflect the exception if a response
  is successfully generated by the method.
  This is a very minor incompatibility. Most tweens right now would give
  priority to the raised exception and ignore ``request.exception``. This
  change just improves and clarifies that bookkeeping by trying to be
  more clear about the relationship between the response and its squashed
  exception. See https://github.com/Pylons/pyramid/pull/3029 and
  https://github.com/Pylons/pyramid/pull/3031
Documentation Changes
---------------------
CONTRIBUTORS.txt
@@ -297,6 +297,14 @@
- Kirill Kuzminykh, 2017/03/01
- Aleph Melo, 2017/04/16
- Jeremy(Ching-Rui) Chen, 2017/04/19
- Russell Ballestrini, 2017/05/06
- Fang-Pen Lin, 2017/05/22
- Volker Diels-Grabsch, 2017/06/09
- Denis Rykov, 2017/06/15
README.rst
@@ -3,15 +3,11 @@
.. image:: https://travis-ci.org/Pylons/pyramid.png?branch=1.9-branch
        :target: https://travis-ci.org/Pylons/pyramid
        :alt: master Travis CI Status
        :alt: 1.9-branch Travis CI Status
.. image:: https://readthedocs.org/projects/pyramid/badge/?version=1.9-branch
        :target: http://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/
        :alt: Master Documentation Status
.. image:: https://readthedocs.org/projects/pyramid/badge/?version=1.9-branch
        :target: http://docs.pylonsproject.org/projects/pyramid/en/1.9-branch/
        :alt: Latest Documentation Status
        :alt: 1.9-branch Documentation Status
.. image:: https://img.shields.io/badge/irc-freenode-blue.svg
        :target: https://webchat.freenode.net/?channels=pyramid
@@ -38,7 +34,7 @@
       server = make_server('0.0.0.0', 8080, app)
       server.serve_forever()
Pyramid is a project of the `Pylons Project <http://pylonsproject.org/>`_.
Pyramid is a project of the `Pylons Project <https://pylonsproject.org>`_.
Support and Documentation
-------------------------
RELEASING.txt
@@ -38,6 +38,14 @@
  $ ./scaffoldtests.sh
- For each ``pyramid-cookiecutter-*``, make a new branch off "master" with the
  same name to align with the new Pyramid release branch name.
- In the docs, update the ``cookiecutter`` command with the new branch name,
  for example, ``cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout
  x.y-branch``. A search for ``cookiecutter gh:Pylons/pyramid-cookiecutter-``
  should return all instances to be updated.
- Ensure all features of the release are documented (audit CHANGES.txt or
  communicate with contributors).
@@ -48,8 +56,8 @@
  include a link under "Bug Fix Releases" to the minor feature
  changes in CHANGES.txt.
- Update README.rst to use correct versions of badges and URLs according to
  each branch and context, i.e., RTD "latest" == GitHub/Travis "1.x-branch".
- Update README.rst to use correct versions of badges, URLs, and ALT option
  according to the new release branch name.
- Update whatsnew-X.X.rst in docs to point at change log entries for individual
  releases if applicable.
@@ -96,6 +104,14 @@
- Change setup.py version to the next version number.
- Update README.rst to use correct versions of badges, URLs, and ALT option
  for "master" instead of the major release version.
- In the docs, update the ``cookiecutter`` command with ``master``,
  for example, ``cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout
  master``. A search for ``cookiecutter gh:Pylons/pyramid-cookiecutter-``
  should return all instances to be updated.
Update previous version (final releases only)
---------------------------------------------
contributing.md
@@ -3,7 +3,7 @@
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) and
Contribute](https://pylonsproject.org/community-how-to-contribute.html) and
[Coding Style and
Standards](http://docs.pylonsproject.org/en/latest/community/codestyle.html).
docs/api/security.rst
@@ -80,15 +80,23 @@
    'george', 'read')`` that means deny access.  A sequence of ACEs
    makes up an ACL.  It is a string, and its actual value is "Deny".
.. autoclass:: ACLDenied
   :members:
.. autoclass:: ACLAllowed
   :members:
.. autoclass:: Denied
   :members:
   :members: msg
   .. automethod:: __new__
.. autoclass:: Allowed
   :members:
   :members: msg
   .. automethod:: __new__
.. autoclass:: ACLDenied
   :members: msg
   .. automethod:: __new__
.. autoclass:: ACLAllowed
   :members: msg
   .. automethod:: __new__
docs/conf.py
@@ -70,7 +70,7 @@
    'plaster': ('http://docs.pylonsproject.org/projects/plaster/en/latest/', None),
    'pylonswebframework': ('http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/', None),
    'python': ('https://docs.python.org/3', None),
    'pytest': ('http://pytest.org/latest/', None),
    'pytest': ('https://pytest.org/en/latest/', None),
    'sphinx': ('http://www.sphinx-doc.org/en/latest', None),
    'sqla': ('http://docs.sqlalchemy.org/en/latest', None),
    'tm': ('http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/', None),
docs/glossary.rst
@@ -751,7 +751,7 @@
     :ref:`Venusian` is a library which
     allows framework authors to defer decorator actions.  Instead of
     taking actions when a function (or class) decorator is executed
     at import time, the action usually taken by the decorator is
     at :term:`import time`, the action usually taken by the decorator is
     deferred until a separate "scan" phase.  :app:`Pyramid` relies
     on Venusian to provide a basis for its :term:`scan` feature.
@@ -1172,3 +1172,34 @@
      A policy which wraps the :term:`router` by creating the request object
      and sending it through the request pipeline.
      See :class:`pyramid.config.Configurator.set_execution_policy`.
   singleton
      A singleton is a class which will only ever have one instance.
      As there is only one, it is shared by all other code.
      This makes it an example of :term:`global state`.
      Using a singleton is `considered a poor design choice. <https://softwareengineering.stackexchange.com/questions/148108/why-is-global-state-so-evil>`_
      As :term:`mutable` global state, it can be changed by any other code,
      and so the values it represents cannot be reasoned about or tested properly.
   global state
      A set of values that are available to the entirety of a program.
   mutable
      In Python, a value is mutable if it can be changed *in place*.
      The Python ``list`` and ``dict`` types are mutable.
      When a value is added to or removed from an instance of either, the original object remains.
      The opposite of mutable is :term:`immutable`.
   immutable
      In Python, a value is immutable if it cannot be changed.
      The Python ``str``, ``int``, and ``tuple`` data types are all ``immutable``.
   import time
      In Python, the moment when a module is referred to in an ``import`` statement.
      At this moment, all statements in that module at the module scope (at the left margin) are executed.
      It is a bad design decision to put statements in a Python module that have :term:`side effect`\ s at import time.
   side effect
      A statement or function has a side effect when it changes a value outside its own scope.
      Put another way, if one can observe the change made by a function from outside that function, it has a side effect.
docs/index.rst
@@ -5,7 +5,7 @@
=========================
:app:`Pyramid` is a small, fast, down-to-earth Python web framework.  It is
developed as part of the `Pylons Project <http://pylonsproject.org/>`_.
developed as part of the `Pylons Project <https://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:
@@ -95,9 +95,7 @@
  # 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>`_.
To find out how to become a contributor to :app:`Pyramid`, please see `How to Contribute Source Code and Documentation <https://pylonsproject.org/community-how-to-contribute.html>`_.
.. _html_narrative_documentation:
docs/narr/advanced-features.rst
New file
@@ -0,0 +1,330 @@
Advanced :app:`Pyramid` Design Features
=======================================
:app:`Pyramid` has been built from the ground up to avoid the problems that other frameworks can suffer.
You Don't Need Singletons
-------------------------
Have you ever struggled with parameterizing Django's ``settings.py`` file for multiple installations of the same Django application? Have you ever needed to monkey-patch a framework fixture to get it to behave properly for your use case? Have you ever tried to deploy your application using an asynchronous server and failed?
All these problems are symptoms of :term:`mutable` :term:`global state`, also known as :term:`import time` :term:`side effect`\ s and arise from the use of :term:`singleton` data structures.
:app:`Pyramid` is written so that you don't run into these types of problems. It is even possible to run multiple copies of the *same* :app:`Pyramid` application configured differently within a single Python process. This makes running :app:`Pyramid` in shared hosting environments a snap.
Simplify your View Code with Predicates
---------------------------------------
How many times have you found yourself beginning the logic of your view code with something like this:
.. code-block:: python
    :linenos:
    if request.user.is_authenticated:
        # do one thing
    else:
        # do something else
Unlike many other systems, :app:`Pyramid` allows you to associate more than one view with a single route. For example, you can create a route with the pattern ``/items`` and when the route is matched, you can send the request to one view if the request method is GET, another view if the request method is POST, and so on.
:app:`Pyramid` uses a system of :term:`view predicate`\ s to allow this. Matching the request method is one basic thing you can do with a :term:`view predicate`. You can also associate views with other request parameters, such as elements in the query string, the Accept header, whether the request is an AJAX (XHR) request or not, and lots of other things.
For our example above, you can do this instead:
.. code-block:: python
    :linenos:
    @view_config(route_name="items", effective_principals=pyramid.security.Authenticated)
    def auth_view(request):
        # do one thing
    @view_config(route_name="items")
    def anon_view(request):
        # do something else
This approach allows you to develop view code that is simpler, more easily understandable, and more directly testable.
.. seealso::
   See also :ref:`view_configuration_parameters`.
Stop Worrying About Transactions
--------------------------------
:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a *transaction management* system.  When you use this system, you can stop worrying about when to commit your changes, :app:`Pyramid` handles it for you. The system will commit at the end of a request or abort if there was an exception.
Why is that a good thing? Imagine a situation where you manually commit a change to your persistence layer. It's very likely that other framework code will run *after* your changes are done. If an error happens in that other code, you can easily wind up with inconsistent data if you're not extremely careful.
Using transaction management saves you from needing to think about this. Either a request completes successfully and all changes are committed, or it does not and all changes are aborted.
:app:`Pyramid`\ 's transaction management is extendable, so you can synchronize commits between multiple databases or databases of different kinds. It also allows you to do things like conditionally send email if a transaction is committed, but otherwise keep quiet.
.. seealso::
   See also :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements anywhere in application code).
Stop Worrying About Configuration
---------------------------------
When a system is small, it's reasonably easy to keep it all in your head. But as systems grow large, configuration grows more complex. Your app may grow to have hundreds or even thousands of configuration statements.
:app:`Pyramid`\ 's configuration system keeps track of each of your statements. If you accidentally add two that are identical, or :app:`Pyramid` can't make sense out of what it would mean to have both statements active at the same time, it will complain loudly at startup time.
:app:`Pyramid`\ 's configuration system is not dumb though. If you use the :meth:`~pyramid.config.Configurator.include` system, it can automatically resolve conflicts on its own. More local statements are preferred over less local ones. So you can intelligently factor large systems into smaller ones.
.. seealso::
   See also :ref:`conflict_detection`.
Compose Powerful Apps From Simple Parts
----------------------------------------
Speaking of the :app:`Pyramid` structured :meth:`~pyramid.config.Configurator.include` mechanism, it allows you to compose complex applications from multiple, simple Python packages. All the configuration statements that can be performed in your main :app:`Pyramid` application can also be used in included packages. You can add views, routes, and subscribers, and even set authentication and authorization policies.
If you need, you can extend or override the configuration of an existing application by including its configuration in your own and then modifying it.
For example, if you want to reuse an existing application that already has a bunch of routes, you can just use the ``include`` statement with a ``route_prefix``. All the routes of that application will be availabe, prefixed as you requested:
.. code-block:: python
    :linenos:
    from pyramid.config import Configurator
    if __name__ == '__main__':
       config = Configurator()
       config.include('pyramid_jinja2')
       config.include('pyramid_exclog')
       config.include('some.other.package', route_prefix='/somethingelse')
.. seealso::
    See also :ref:`including_configuration` and :ref:`building_an_extensible_app`.
Authenticate Users Your Way
---------------------------
:app:`Pyramid` ships with prebuilt, well-tested authentication and authorization schemes out of the box. Using a scheme is a matter of configuration. So if you need to change approaches later, you need only update your configuration.
In addition, the system that handles authentication and authorization is flexible and pluggable. If you want to use another security add-on, or define your own, you can. And again, you need only update your application configuration to make the change.
.. seealso::
   See also :ref:`enabling_authorization_policy`.
Build Trees of Resources
------------------------
:app:`Pyramid` supports :term:`traversal`, a way of mapping URLs to a concrete :term:`resource tree`. If your application naturally consists of an arbitrary heirarchy of different types of content (like a CMS or a Document Management System), traversal is for you. If you have a requirement for a highly granular security model ("Jane can edit documents in *this* folder, but not *that* one"), traversal can be a powerful approach.
.. seealso::
   See also :ref:`hello_traversal_chapter` and :ref:`much_ado_about_traversal_chapter`.
Take Action on Each Request with Tweens
---------------------------------------
:app:`Pyramid` has a system for applying an arbitrary action to each request or response called a :term:`tween`. The system is similar in concept to WSGI :term:`middleware`, but can be more useful since :term:`tween`\ s run in the :app:`Pyramid` context, and have access to templates, request objects, and other niceties.
The :app:`Pyramid` debug toolbar is a :term:`tween`, as is the ``pyramid_tm`` transaction manager.
.. seealso::
   See also :ref:`registering_tweens`.
Return What You Want From Your Views
------------------------------------
We have shown elsewhere (in the :doc:`introduction`) how using a :term:`renderer` allows you to return simple Python dictionaries from your view code. But some frameworks allow you to return strings or tuples from view callables. When frameworks allow for this, code looks slightly prettier because there are fewer imports and less code. For example, compare this:
.. code-block:: python
    :linenos:
    from pyramid.response import Response
    def aview(request):
        return Response("Hello world!")
To this:
.. code-block:: python
    :linenos:
    def aview(request):
        return "Hello world!"
Nicer to look at, right?
Out of the box, :app:`Pyramid` will raise an exception if you try to run the second example above. After all, a view should return a response, and "explicit is better than implicit".
But if you're a developer who likes the aesthetics of simplicity, :app:`Pyramid` provides a way to support this sort of thing, the :term:`response adapter`\ :
.. code-block:: python
    :linenos:
    from pyramid.config import Configurator
    from pyramid.response import Response
    def string_response_adapter(s):
        response = Response(s)
        response.content_type = 'text/html'
        return response
A new response adapter is registered in configuration:
.. code-block:: python
    :linenos:
    if __name__ == '__main__':
        config = Configurator()
        config.add_response_adapter(string_response_adapter, str)
With that, you may return strings from any of your view callables, e.g.:
.. code-block:: python
    :linenos:
    def helloview(request):
        return "Hello world!"
    def goodbyeview(request):
        return "Goodbye world!"
You can even use a :term:`response adapter` to allow for custom content types and return codes:
.. code-block:: python
    :linenos:
    from pyramid.config import Configurator
    def tuple_response_adapter(val):
        status_int, content_type, body = val
        response = Response(body)
        response.content_type = content_type
        response.status_int = status_int
        return response
    def string_response_adapter(body):
        response = Response(body)
        response.content_type = 'text/html'
        response.status_int = 200
        return response
    if __name__ == '__main__':
        config = Configurator()
        config.add_response_adapter(string_response_adapter, str)
        config.add_response_adapter(tuple_response_adapter, tuple)
With this, both of these views will work as expected:
.. code-block:: python
    :linenos:
    def aview(request):
        return "Hello world!"
    def anotherview(request):
        return (403, 'text/plain', "Forbidden")
.. seealso::
   See also :ref:`using_iresponse`.
Use Global Response Objects
---------------------------
Views have to return responses. But constructing them in view code is a chore. And perhaps registering a :term:`response adapter` as shown above is just too much work. :app:`Pyramid` provides a global response object as well.  You can use it directly, if you prefer:
.. code-block:: python
    :linenos:
    def aview(request):
        response = request.response
        response.body = 'Hello world!'
        response.content_type = 'text/plain'
        return response
.. seealso::
   See also :ref:`request_response_attr`.
Extend Configuration
--------------------
Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or possibly you would like to add a feature to configuration without asking the core developers to change :app:`Pyramid` itself?
You can extend :app:`Pyramid`\ 's :term:`configurator` with your own directives. For example, let's say you find yourself calling :meth:`pyramid.config.Configurator.add_view` repetitively. Usually you can get rid of the boring with existing shortcuts, but let's say that this is a case where there is no such shortcut:
.. code-block:: python
    :linenos:
    from pyramid.config import Configurator
    config = Configurator()
    config.add_route('xhr_route', '/xhr/{id}')
    config.add_view('my.package.GET_view', route_name='xhr_route',
                    xhr=True,  permission='view', request_method='GET')
    config.add_view('my.package.POST_view', route_name='xhr_route',
                    xhr=True, permission='view', request_method='POST')
    config.add_view('my.package.HEAD_view', route_name='xhr_route',
                    xhr=True, permission='view', request_method='HEAD')
Pretty tedious right? You can add a directive to the :app:`Pyramid` :term:`configurator` to automate some of the tedium away:
.. code-block:: python
    :linenos:
    from pyramid.config import Configurator
    def add_protected_xhr_views(config, module):
        module = config.maybe_dotted(module)
        for method in ('GET', 'POST', 'HEAD'):
            view = getattr(module, 'xhr_%s_view' % method, None)
            if view is not None:
                config.add_view(view, route_name='xhr_route', xhr=True,
                                permission='view', request_method=method)
    config = Configurator()
    config.add_directive('add_protected_xhr_views', add_protected_xhr_views)
Once that's done, you can call the directive you've just added as a method of the :term:`configurator` object:
.. code-block:: python
    :linenos:
    config.add_route('xhr_route', '/xhr/{id}')
    config.add_protected_xhr_views('my.package')
Much better!
You can share your configuration code with others, too. Add your code to a Python package. Put the call to :meth:`~pyramid.config.Configurator.add_directive` in a function. When other programmers install your package, they'll be able to use your configuration by passing your function to a call to :meth:`~pyramid.config.Configurator.include`.
.. seealso::
    See also :ref:`add_directive`.
Introspect Your Application
---------------------------
If you're building a large, pluggable system, it's useful to be able to get a list of what has been plugged in *at application runtime*. For example, you might want to show users a set of tabs at the top of the screen based on a list of the views they registered.
:app:`Pyramid` provides an :term:`introspector` for just this purpose.
Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within a view:
.. code-block:: python
    :linenos:
    from pyramid.view import view_config
    from pyramid.response import Response
    @view_config(route_name='bar')
    def show_current_route_pattern(request):
        introspector = request.registry.introspector
        route_name = request.matched_route.name
        route_intr = introspector.get('routes', route_name)
        return Response(str(route_intr['pattern']))
.. seealso::
    See also :ref:`using_introspection`.
docs/narr/install.rst
@@ -206,9 +206,7 @@
   ``$VENV/bin/pip`` clearly specifies that ``pip`` is run from within the
   virtual environment and not at the system level.
   ``activate`` drops turds into the user's shell environment, leaving them
   vulnerable to executing commands in the wrong context. ``deactivate`` might
   not correctly restore previous shell environment variables.
   ``activate`` makes changes to the user's shell environment which can often be convenient. However, in the context of long-form documentation, environment configuration can easily be forgotten. By keeping each snippet explicit we can reduce copy / paste errors by users in which commands are executed against the wrong Python environment. Also, ``deactivate`` might not correctly restore previous shell environment variables. Avoiding ``activate`` keeps the environment more reproducible.
   Although using ``source bin/activate``, then ``pip``, requires fewer key
   strokes to issue commands once invoked, there are other things to consider.
docs/narr/introduction.rst
@@ -9,112 +9,87 @@
:app:`Pyramid` Introduction
===========================
:app:`Pyramid` is a general, open source, Python web application development
*framework*. Its primary goal is to make it easier for a Python developer to
create web applications.
:app:`Pyramid` is a Python web application *framework*. It is designed to make creating web applications easier. It is open source.
.. sidebar:: Frameworks vs. Libraries
.. sidebar:: What Is a Framework?
   A *framework* differs from a *library* in one very important way: library
   code is always *called* by code that you write, while a framework always
   *calls* code that you write.  Using a set of libraries to create an
   application is usually easier than using a framework initially, because you
   can choose to cede control to library code you have not authored very
   selectively. But when you use a framework, you are required to cede a
   greater portion of control to code you have not authored: code that resides
   in the framework itself.  You needn't use a framework at all to create a web
   application using Python.  A rich set of libraries already exists for the
   platform.  In practice, however, using a framework to create an application
   is often more practical than rolling your own via a set of libraries if the
   framework provides a set of facilities that fits your application
   requirements.
   A *framework* provides capabilities that developers can enhance or extend. A web application framework provides many of the common needs of building web applications allowing developers to concentrate only on the parts that are specific to their application.
Pyramid attempts to follow these design and engineering principles:
   Every framework makes choices about how a particular problem should be solved. When developers choose to use a framework, they cede control over the portions of their application that are provided by the framework. It is possible to write a complete web application without any framework, by using Python libraries. In practice, however, it is often more practical to use a framework, so long as your chosen framework fits the requirements of your application.
:app:`Pyramid` follows these design and engineering principles:
Simplicity
  :app:`Pyramid` takes a *"pay only for what you eat"* approach.  You can get
  results even if you have only a partial understanding of :app:`Pyramid`.  It
  doesn't force you to use any particular technology to produce an application,
  and we try to keep the core set of concepts that you need to understand to a
  minimum.
   :app:`Pyramid` is designed to be easy to use. You can get started even if you don't understand it all. And when you're ready to do more, :app:`Pyramid` will be there for you.
Minimalism
  :app:`Pyramid` tries to solve only the fundamental problems of creating a web
  application: the mapping of URLs to code, templating, security, and serving
  static assets. We consider these to be the core activities that are common to
  nearly all web applications.
   Out of the box, :app:`Pyramid` provides only the core tools needed for nearly all web applications: mapping URLs to code, security, and serving static assets (files like JavaScript and CSS). Additional tools provide templating, database integration and more. But with :app:`Pyramid` you can *"pay only for what you eat"*.
Documentation
  Pyramid's minimalism means that it is easier for us to maintain complete and
  up-to-date documentation. It is our goal that no aspect of Pyramid is
  undocumented.
   :app:`Pyramid` is committed to comprehensive and up-to-date documentation.
Speed
  :app:`Pyramid` is designed to provide noticeably fast execution for common
  tasks such as templating and simple response generation.
  :app:`Pyramid` is designed to be noticeably fast.
Reliability
  :app:`Pyramid` is developed conservatively and tested exhaustively. Where
  Pyramid source code is concerned, our motto is: "If it ain't tested, it's
  broke".
  :app:`Pyramid` is developed conservatively and tested exhaustively. Our motto is: "If it ain't tested, it's broke".
Openness
  As with Python, the Pyramid software is distributed under a `permissive open
  source license <http://repoze.org/license.html>`_.
  As with Python, the :app:`Pyramid` software is distributed under a `permissive open source license <http://repoze.org/license.html>`_.
.. _why_pyramid:
Why Pyramid?
------------
In a world filled with web frameworks, why should you choose :app:`Pyramid`\ ?
Modern
~~~~~~
:app:`Pyramid` is fully compatible with Python 3. If you develop a :app:`Pyramid` application today, you can rest assured that you'll be able to use the most modern features of your favorite language. And in the years to come, you'll continue to bed working on a framework that is up-to-dateand forward-looking.
Tested
~~~~~~
Untested code is broken by design. The :app:`Pyramid` community has a strong testing culture and our framework reflects that. Every release of :app:`Pyramid` has 100% statement coverage (as measured by `coverage <https://coverage.readthedocs.io>`_) and 95% decision/condition coverage. (as measured by `instrumental <http://instrumental.readthedocs.io/en/latest/intro.html>`_) It is automatically tested using `Travis <https://travis-ci.org/Pylons/pyramid>`_ and `Jenkins <http://jenkins.pylonsproject.org/job/pyramid/>`_ on supported versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons <https://trypyramid.com/resources-extending-pyramid.html>`_ are held to a similar testing standard.
We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of them while working on projects with a solid testing regime.
Documented
~~~~~~~~~~
The :app:`Pyramid` documentation is comprehensive. We strive to keep our narrative documentation both complete and friendly to newcomers. We also maintain the :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>` of  recipes demonstrating common scenarios you might face. Contributions in the form of improvements to our documentation are always appreciated. And we always welcome improvements to our `official tutorials <html_tutorials>`_ as well as new contributions to our `community maintained tutorials <tutorials:pyramid-tutorials>`_.
Supported
~~~~~~~~~
You can get help quickly with :app:`Pyramid`. It's our goal that no :app:`Pyramid` question go unanswered. Whether you ask a question on IRC, on the Pylons-discuss mailing list, or on StackOverflow, you're likely to get a reasonably prompt response.
:app:`Pyramid` is also a welcoming, friendly space for newcomers. We don't tolerate "support trolls" or those who enjoy berating fellow users in our support channels. We try to keep it well-lit and new-user-friendly.
.. seealso::
    See also our `#pyramid IRC channel <https://webchat.freenode.net/?channels=pyramid>`_, our `pylons-discuss mailing list <https://groups.google.com/forum/#!forum/pylons-discuss>`_, and :ref:`support-and-development`.
.. _what_makes_pyramid_unique:
What makes Pyramid unique
-------------------------
Understandably, people don't usually want to hear about squishy engineering
principles; they want to hear about concrete stuff that solves their problems.
With that in mind, what would make someone want to use Pyramid instead of one
of the many other web frameworks available today?  What makes Pyramid unique?
There are many tools available for web development. What would make someone want to use :app:`Pyramid` instead?  What makes :app:`Pyramid` unique?
This is a hard question to answer because there are lots of excellent choices,
and it's actually quite hard to make a wrong choice, particularly in the Python
web framework market.  But one reasonable answer is this: you can write very
small applications in Pyramid without needing to know a lot. "What?" you say.
"That can't possibly be a unique feature. Lots of other web frameworks let you
do that!"  Well, you're right.  But unlike many other systems, you can also
write very large applications in Pyramid if you learn a little more about it.
Pyramid will allow you to become productive quickly, and will grow with you. It
won't hold you back when your application is small, and it won't get in your
way when your application becomes large.  "Well that's fine," you say. "Lots of
other frameworks let me write large apps, too."  Absolutely.  But other Python
web frameworks don't seamlessly let you do both.  They seem to fall into two
non-overlapping categories: frameworks for "small apps" and frameworks for "big
apps".  The "small app" frameworks typically sacrifice "big app" features, and
vice versa.
With :app:`Pyramid` you can write very small applications without needing to know a lot. And by learning a bit more, you can write very large applications too. :app:`Pyramid` will allow you to become productive quickly, and will grow with you. It won't hold you back when your application is small, and it won't get in your way when your application becomes large. Other application frameworks seem to fall into two non-overlapping categories: those that support "small apps" and those designed for "big apps".
We don't think it's a universally reasonable suggestion to write "small apps"
in a "small framework" and "big apps" in a "big framework".  You can't really
know to what size every application will eventually grow.  We don't really want
to have to rewrite a previously small application in another framework when it
gets "too big".  We believe the current binary distinction between frameworks
for small and large applications is just false. A well-designed framework
should be able to be good at both.  Pyramid strives to be that kind of
framework.
We don't believe you should have to make this choice. You can't really know how large your application will become.  You certainly shouldn't have to rewrite a small application in another framework when it gets "too big". A well-designed framework should be able to be good at both. :app:`Pyramid` is that kind of framework.
To this end, Pyramid provides a set of features that combined are unique
amongst Python web frameworks.  Lots of other frameworks contain some
combination of these features. Pyramid of course actually stole many of them
from those other frameworks.  But Pyramid is the only one that has all of them
in one place, documented appropriately, and useful *à la carte* without
necessarily paying for the entire banquet.  These are detailed below.
:app:`Pyramid` provides a set of features that are unique among Python web frameworks. Others may provide some, but only :app:`Pyramid` provides them all, in one place, fully documented, and *à la carte* without needing to pay for the whole banquet.
Single-file applications
~~~~~~~~~~~~~~~~~~~~~~~~
You can write a Pyramid application that lives entirely in one Python file, not
unlike existing Python microframeworks.  This is beneficial for one-off
prototyping, bug reproduction, and very small applications.  These applications
are easy to understand because all the information about the application lives
in a single place, and you can deploy them without needing to understand much
about Python distributions and packaging.  Pyramid isn't really marketed as a
microframework, but it allows you to do almost everything that frameworks that
are marketed as "micro" offer in very similar ways.
Build single-file applications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can write a :app:`Pyramid` application that lives entirely in one Python file. Such an application is easy to understand since everything is in one place. It is easy to deploy because you don't need to know much about Python packaging. :app:`Pyramid` allows you to do almost everything that so-called *microframeworks* can in very similar ways.
.. literalinclude:: helloworld.py
@@ -122,13 +97,10 @@
    See also :ref:`firstapp_chapter`.
Decorator-based configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configure applications with decorators
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you like the idea of framework configuration statements living next to the
code it configures, so you don't have to constantly switch between files to
refer to framework configuration when adding new code, you can use Pyramid
decorators to localize the configuration.  For example:
:app:`Pyramid` allows you to keep your configuration right next to your code. That way you don't have to switch files to see your configuration. For example:
.. code-block:: python
@@ -139,103 +111,74 @@
   def fred_view(request):
       return Response('fred')
However, unlike some other systems, using decorators for Pyramid configuration
does not make your application difficult to extend, test, or reuse.  The
:class:`~pyramid.view.view_config` decorator, for example, does not actually
*change* the input or output of the function it decorates, so testing it is a
"WYSIWYG" operation. You don't need to understand the framework to test your
own code. You just behave as if the decorator is not there.  You can also
instruct Pyramid to ignore some decorators, or use completely imperative
configuration instead of decorators to add views. Pyramid decorators are inert
instead of eager. You detect and activate them with a :term:`scan`.
However, using :app:`Pyramid` configuration decorators does not change your code. It remains easy to extend, test, or reuse. You can test your code as if the decorators were not there. You can instruct the framework to ignore some decorators. You can even use an imperative style to write your configuration, skipping decorators entirely.
Example: :ref:`mapping_views_using_a_decorator_section`.
.. seealso::
URL generation
~~~~~~~~~~~~~~
    See also :ref:`mapping_views_using_a_decorator_section`.
Pyramid is capable of generating URLs for resources, routes, and static assets.
Its URL generation APIs are easy to use and flexible.  If you use Pyramid's
various APIs for generating URLs, you can change your configuration around
arbitrarily without fear of breaking a link on one of your web pages.
Generate application URLs
~~~~~~~~~~~~~~~~~~~~~~~~~
Example: :ref:`generating_route_urls`.
Dynamic web applications produce URLs that can change depending on what you are viewing. :app:`Pyramid` provides flexible, consistent, easy to use tools for generating URLs. When you use these tools to write your application, you can change your configuration without fear of breaking links in your web pages.
Static file serving
.. seealso::
    See also :ref:`generating_route_urls`.
Serve static assets
~~~~~~~~~~~~~~~~~~~
Pyramid is perfectly willing to serve static files itself.  It won't make you
use some external web server to do that.  You can even serve more than one set
of static files in a single Pyramid web application (e.g., ``/static`` and
``/static2``).  You can optionally place your files on an external web server
and ask Pyramid to help you generate URLs to those files. This let's you use
Pyramid's internal file serving while doing development, and a faster static
file server in production, without changing any code.
Web applications often require JavaScript, CSS, images and other so-called *static assets*. :app:`Pyramid` provides flexible tools for serving these kinds of files. You can serve them directly from :app:`Pyramid`, or host them on an external server or CDN (content delivery network). Either way, :app:`Pyramid` can help you to generate URLs so you can change where your files come from without changing any code.
Example: :ref:`static_assets_section`.
.. seealso::
Fully interactive development
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    See also :ref:`static_assets_section`.
When developing a Pyramid application, several interactive features are
available. Pyramid can automatically utilize changed templates when rendering
pages and automatically restart the application to incorporate changed Python
code. Plain old ``print()`` calls used for debugging can display to a console.
Develop interactively
~~~~~~~~~~~~~~~~~~~~~
Pyramid's debug toolbar comes activated when you use a Pyramid :term:`cookiecutter` to
render a project.  This toolbar overlays your application in the browser, and
allows you access to framework data, such as the routes configured, the last
renderings performed, the current set of packages installed, SQLAlchemy queries
run, logging data, and various other facts.  When an exception occurs, you can
use its interactive debugger to poke around right in your browser to try to
determine the cause of the exception.  It's handy.
:app:`Pyramid` can automatically detect changes you make to template files and code, so your changes are immediately available in your browser. You can debug using plain old ``print()`` calls, which will display to your console.
Example: :ref:`debug_toolbar`.
:app:`Pyramid` has a debug toolbar that allows you to see information about how your application is working right in your browser. See configuration, installed packages, SQL queries, logging statements and more.
Debugging settings
~~~~~~~~~~~~~~~~~~
When your application has an error, an interactive debugger allows you to poke around from your browser to find out what happened.
Pyramid has debugging settings that allow you to print Pyramid runtime
information to the console when things aren't behaving as you're expecting. For
example, you can turn on ``debug_notfound``, which prints an informative
message to the console every time a URL does not match any view.  You can turn
on ``debug_authorization``, which lets you know why a view execution was
allowed or denied by printing a message to the console.  These features are
useful for those WTF moments.
To use the :app:`Pyramid` debug toolbar, build your project with a :app:`Pyramid` :term:`cookiecutter`.
There are also a number of commands that you can invoke within a Pyramid
environment that allow you to introspect the configuration of your system.
``proutes`` shows all configured routes for an application in the order they'll
be evaluated for matching. ``pviews`` shows all configured views for any given
URL.  These are also WTF-crushers in some circumstances.
.. seealso::
Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`.
    See also :ref:`debug_toolbar`.
Add-ons
~~~~~~~
Debug with power
~~~~~~~~~~~~~~~~
Pyramid has an extensive set of add-ons held to the same quality standards as
the Pyramid core itself.  Add-ons are packages which provide functionality that
the Pyramid core doesn't.  Add-on packages already exist which let you easily
send email, let you use the Jinja2 templating system, let you use XML-RPC or
JSON-RPC, let you integrate with jQuery Mobile, etc.
When things go wrong, :app:`Pyramid` gives you powerful ways to fix the problem.
Examples:
https://trypyramid.com/resources-extending-pyramid.html
You can configure :app:`Pyramid` to print helpful information to the console. The ``debug_notfound`` setting shows information about URLs that aren't matched. The ``debug_authorization`` setting provides helpful messages about why you aren't allowed to do what you just tried.
Class-based and function-based views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:app:`Pyramid` also has command line tools to help you verify your configuration. You can use ``proutes`` and ``pviews`` to inspect how URLs are connected to your application code.
Pyramid has a structured, unified concept of a :term:`view callable`. View
callables can be functions, methods of classes, or even instances.  When you
add a new view callable, you can choose to make it a function or a method of a
class. In either case Pyramid treats it largely the same way.  You can change
your mind later and move code between methods of classes and functions.  A
collection of similar view callables can be attached to a single class as
methods, if that floats your boat, and they can share initialization code as
necessary.  All kinds of views are easy to understand and use, and operate
similarly.  There is no phony distinction between them. They can be used for
the same purposes.
.. seealso::
    See also :ref:`debug_authorization_section`, :ref:`command_line_chapter`,
    and :doc:`../pscripts/index`
Extend your application
~~~~~~~~~~~~~~~~~~~~~~~
:app:`Pyramid` add-ons extend the core of the framework with useful abilities. There are add-ons available for your favorite template language, SQL and NoSQL databases, authentication services and more.
Supported :app:`Pyramid` add-ons are held to the same demanding standards as the framework itself. You will find them to be fully tested and well documented.
.. seealso::
    See also https://trypyramid.com/resources-extending-pyramid.html
Write your views, *your* way
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A fundamental task for any framework is to map URLs to code. In :app:`Pyramid`, that code is called a :term:`view callable`. View callables can be functions, class methods or even callable class instances. You are free to choose the approach that best fits your use case. Regardless of your choice, :app:`Pyramid` treats them the same. You can change your mind at any time without any penalty. There are no artificial distinctions between the various approaches.
Here's a view callable defined as a function:
@@ -275,54 +218,30 @@
.. _intro_asset_specs:
Asset specifications
~~~~~~~~~~~~~~~~~~~~
Find *your* static assets
~~~~~~~~~~~~~~~~~~~~~~~~~
Asset specifications are strings that contain both a Python package name and a
file or directory name, e.g., ``MyPackage:static/index.html``.  Use of these
specifications is omnipresent in Pyramid.  An asset specification can refer to
a template, a translation directory, or any other package-bound static
resource.  This makes a system built on Pyramid extensible because you don't
have to rely on globals ("*the* static directory") or lookup schemes ("*the*
ordered set of template directories") to address your files.  You can move
files around as necessary, and include other packages that may not share your
system's templates or static files without encountering conflicts.
In many web frameworks, the static assets required by an application are kept in a globally shared location, "the *static* directory". Others use a lookup scheme, like an ordered set of template directories. Both of these approaches have problems when it comes to customization.
Because asset specifications are used heavily in Pyramid, we've also provided a
way to allow users to override assets.  Say you love a system that someone else
has created with Pyramid but you just need to change "that one template" to
make it all better.  No need to fork the application.  Just override the asset
specification for that template with your own inside a wrapper, and you're good
to go.
:app:`Pyramid` takes a different approach. Static assets are located using *asset specifications*, strings that contain reference both to a Python package name and a file or directory name, e.g. ``MyPackage:static/index.html``. These specifications are used for templates, JavaScript and CSS, translation files, and any other package-bound static resource. By using asset specifications, :app:`Pyramid` makes it easy to extend your application with other packages without worrying about conflicts.
What happens if another :app:`Pyramid` package you are using provides an asset you need to customize? Maybe that page template needs better HTML, or you want to update some CSS. With asset specifications you can override the assets from other packages using simple wrappers.
Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`.
Extensible templating
~~~~~~~~~~~~~~~~~~~~~
Use *your* templates
~~~~~~~~~~~~~~~~~~~~
Pyramid has a structured API that allows for pluggability of "renderers".
Templating systems such as Mako, Genshi, Chameleon, and Jinja2 can be treated
as renderers.  Renderer bindings for all of these templating systems already
exist for use in Pyramid.  But if you'd rather use another, it's not a big
deal.  Just copy the code from an existing renderer package, and plug in your
favorite templating system.  You'll then be able to use that templating system
from within Pyramid just as you'd use one of the "built-in" templating systems.
In :app:`Pyramid`, the job of creating a ``Response`` belongs to a :term:`renderer`. Any templating system—Mako, Chameleon, Jinja2—can be a renderer. In fact, packages exist for all of these systems. But if you'd rather use another, a structured API exists allowing you to create a renderer using your favorite templating system. You can use the templating system *you* understand, not one required by the framework.
Pyramid does not make you use a single templating system exclusively.  You can
use multiple templating systems, even in the same project.
What's more, :app:`Pyramid` does not make you use a single templating system exclusively.  You can use multiple templating systems, even in the same project.
Example: :ref:`templates_used_directly`.
Rendered views can return dictionaries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Write testable views
~~~~~~~~~~~~~~~~~~~~
If you use a :term:`renderer`, you don't have to return a special kind of
"webby" ``Response`` object from a view.  Instead you can return a dictionary,
and Pyramid will take care of converting that dictionary to a Response using a
template on your behalf.  This makes the view easier to test, because you don't
have to parse HTML in your tests. Instead just make an assertion that the view
returns "the right stuff" in the dictionary.  You can write "real" unit tests
instead of functionally testing all of your views.
When you use a :term:`renderer` with your view callable, you are freed from needing to return a "webby" ``Response`` object. Instead your views can return a simple Python dictionary. :app:`Pyramid` will take care of rendering the information in that dictionary to a ``Response`` on your behalf. As a result, your views are more easily tested, since you don't need to parse HTML to evaluate the results. :app:`Pyramid` makes it a snap to write unit tests for your views, instead of requiring you to use functional tests.
.. index::
   pair: renderer; explicitly calling
@@ -330,8 +249,7 @@
.. _example_render_to_response_call:
For example, instead of returning a ``Response`` object from a
``render_to_response`` call:
For example, a typical web framework might return a ``Response`` object from a ``render_to_response`` call:
.. code-block:: python
    :linenos:
@@ -342,7 +260,7 @@
        return render_to_response('myapp:templates/mytemplate.pt', {'a':1},
                                  request=request)
You can return a Python dictionary:
While you *can* do this in :app:`Pyramid`, you can also return a Python dictionary:
.. code-block:: python
    :linenos:
@@ -353,547 +271,92 @@
    def myview(request):
        return {'a':1}
When this view callable is called by Pyramid, the ``{'a':1}`` dictionary will
be rendered to a response on your behalf.  The string passed as ``renderer=``
above is an :term:`asset specification`.  It is in the form
``packagename:directoryname/filename.ext``.  In this case, it refers to the
``mytemplate.pt`` file in the ``templates`` directory within the ``myapp``
Python package.  Asset specifications are omnipresent in Pyramid. See
:ref:`intro_asset_specs` for more information.
By configuring your view to use a renderer, you tell :app:`Pyramid` to use the ``{'a':1}`` dictionary and the specified template to render a response on your behalf.
The string passed as ``renderer=`` above is an :term:`asset specification`. Asset specifications are widely used in :app:`Pyramid`. They allow for more reliable customization. See :ref:`intro_asset_specs` for more information.
Example: :ref:`renderers_chapter`.
Event system
~~~~~~~~~~~~
Use events to coordinate actions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid emits *events* during its request processing lifecycle.  You can
subscribe any number of listeners to these events.  For example, to be notified
of a new request, you can subscribe to the ``NewRequest`` event.  To be
notified that a template is about to be rendered, you can subscribe to the
``BeforeRender`` event, and so forth.  Using an event publishing system as a
framework notification feature instead of hardcoded hook points tends to make
systems based on that framework less brittle.
When writing web applications, it is often important to have your code run at a specific point in the lifecycle of a request. In :app:`Pyramid`, you can accomplish this using *subscribers* and *events*.
You can also use Pyramid's event system to send your *own* events.  For
example, if you'd like to create a system that is itself a framework, and may
want to notify subscribers that a document has just been indexed, you can
create your own event type (``DocumentIndexed`` perhaps) and send the event via
Pyramid.  Users of this framework can then subscribe to your event like they'd
subscribe to the events that are normally sent by Pyramid itself.
For example, you might have a job that needs to be done each time your application handles a new request. :app:`Pyramid` emits a ``NewRequest`` event at this point in the request handling lifecycle. You can register your code as a subscriber to this event using a clear, declarative style:
.. code-block:: python
    from pyramid.events import NewRequest
    from pyramid.events import subscriber
    @subscriber(NewRequest)
    def my_job(event):
        do_something(event.request)
:app:`Pyramid`\ 's event system can be extended as well. If you need, you can create events of your own and send them using :app:`Pyramid`\ 's event system. Then anyone working with your application can subscribe to your events and coordinate their code with yours.
Example: :ref:`events_chapter` and :ref:`event_types`.
Built-in internationalization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Build international applications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid ships with internationalization-related features in its core:
localization, pluralization, and creating message catalogs from source files
and templates.  Pyramid allows for a plurality of message catalogs via the use
of translation domains.  You can create a system that has its own translations
without conflict with other translations in other domains.
:app:`Pyramid` ships with internationalization-related features in its core: localization, pluralization, and creating message catalogs from source files and templates.  :app:`Pyramid` allows for a plurality of message catalogs via the use of translation domains.  You can create a system that has its own translations without conflict with other translations in other domains.
Example: :ref:`i18n_chapter`.
HTTP caching
~~~~~~~~~~~~
Build efficient applications
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid provides an easy way to associate views with HTTP caching policies. You
can just tell Pyramid to configure your view with an ``http_cache`` statement,
and it will take care of the rest::
:app:`Pyramid` provides an easy way to *cache* the results of slow or expensive views. You can indicate in view configuration that you want a view to be cached:
   @view_config(http_cache=3600) # 60 minutes
   def myview(request): ....
.. code-block:: python
Pyramid will add appropriate ``Cache-Control`` and ``Expires`` headers to
responses generated when this view is invoked.
    @view_config(http_cache=3600) # 60 minutes
    def myview(request):
        # ...
See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache``
documentation for more information.
:app:`Pyramid` will automatically add the appropriate ``Cache-Control`` and ``Expires`` headers to the response it creates.
Sessions
~~~~~~~~
See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` documentation for more information.
Pyramid has built-in HTTP sessioning.  This allows you to associate data with
otherwise anonymous users between requests.  Lots of systems do this.  But
Pyramid also allows you to plug in your own sessioning system by creating some
code that adheres to a documented interface.  Currently there is a binding
package for the third-party Redis sessioning system that does exactly this. But
if you have a specialized need (perhaps you want to store your session data in
MongoDB), you can.  You can even switch between implementations without
changing your application code.
Build fast applications
~~~~~~~~~~~~~~~~~~~~~~~
Example: :ref:`sessions_chapter`.
Speed
~~~~~
The Pyramid core is, as far as we can tell, at least marginally faster than any
other existing Python web framework.  It has been engineered from the ground up
for speed.  It only does as much work as absolutely necessary when you ask it
to get a job done.  Extraneous function calls and suboptimal algorithms in its
core codepaths are avoided.  It is feasible to get, for example, between 3500
and 4000 requests per second from a simple Pyramid view on commodity dual-core
laptop hardware and an appropriate WSGI server (:term:`mod_wsgi` or gunicorn).  In any
case, performance statistics are largely useless without requirements and
goals, but if you need speed, Pyramid will almost certainly never be your
application's bottleneck; at least no more than Python will be a bottleneck.
The :app:`Pyramid` core is fast. It has been engineered from the ground up for speed. It only does as much work as absolutely necessary when you ask it to get a job done. If you need speed from your application, :app:`Pyramid` is the right choice for you.
Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html
Exception views
~~~~~~~~~~~~~~~
Store session data
~~~~~~~~~~~~~~~~~~
Exceptions happen.  Rather than deal with exceptions that might present
themselves to a user in production in an ad-hoc way, Pyramid allows you to
register an :term:`exception view`.  Exception views are like regular Pyramid
views, but they're only invoked when an exception "bubbles up" to Pyramid
itself.  For example, you might register an exception view for the
:exc:`Exception` exception, which will catch *all* exceptions, and present a
pretty "well, this is embarrassing" page.  Or you might choose to register an
exception view for only specific kinds of application-specific exceptions, such
as an exception that happens when a file is not found, or an exception that
happens when an action cannot be performed because the user doesn't have
permission to do something.  In the former case, you can show a pretty "Not
Found" page; in the latter case you might show a login form.
:app:`Pyramid` has built-in support for HTTP sessions, so you can associate data with specific users between requests. Lots of other frameworks also support sessions. But :app:`Pyramid` allows you to plug in your own custom sessioning system. So long as your system conforms to a documented interface, you can drop it in in place of the provided system.
Currently there is a binding package for the third-party Redis sessioning system that does exactly this. But if you have a specialized need (perhaps you want to store your session data in MongoDB), you can.  You can even switch between implementations without changing your application code.
Example: :ref:`sessions_chapter`.
Handle problems with grace
~~~~~~~~~~~~~~~~~~~~~~~~~~
Mistakes happen. Problems crop up. No one writes bug-free code. :app:`Pyramid`provides a way to handle the exceptions your code encounters. An :term:`exception view` is a special kind of view which is automatically called when a particular exception type arises without being handled by your application.
For example, you might register an exception view for the :exc:`Exception` exception type, which will catch *all* exceptions, and present a pretty "well, this is embarrassing" page.  Or you might choose to register an exception view for only certain application-specific exceptions. You can make one for when a file is not found, or when the user doesn't have permission to do something. In the former case, you can show a pretty "Not Found" page; in the latter case you might show a login form.
Example: :ref:`exception_views`.
No singletons
~~~~~~~~~~~~~
Pyramid is written in such a way that it requires your application to have
exactly zero "singleton" data structures.  Or put another way, Pyramid doesn't
require you to construct any "mutable globals".  Or put even another different
way, an import of a Pyramid application needn't have any "import-time side
effects".  This is esoteric-sounding, but if you've ever tried to cope with
parameterizing a Django ``settings.py`` file for multiple installations of the
same application, or if you've ever needed to monkey-patch some framework
fixture so that it behaves properly for your use case, or if you've ever wanted
to deploy your system using an asynchronous server, you'll end up appreciating
this feature.  It just won't be a problem. You can even run multiple copies of
a similar but not identically configured Pyramid application within the same
Python process.  This is good for shared hosting environments, where RAM is at
a premium.
View predicates and many views per route
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlike many other systems, Pyramid allows you to associate more than one view
per route.  For example, you can create a route with the pattern ``/items`` and
when the route is matched, you can shuffle off the request to one view if the
request method is GET, another view if the request method is POST, etc. A
system known as "view predicates" allows for this.  Request method matching is
the most basic thing you can do with a view predicate.  You can also associate
views with other request parameters, such as the elements in the query string,
the Accept header, whether the request is an XHR request or not, and lots of
other things.  This feature allows you to keep your individual views clean.
They won't need much conditional logic, so they'll be easier to test.
Example: :ref:`view_configuration_parameters`.
Transaction management
And much, much more...
~~~~~~~~~~~~~~~~~~~~~~
A couple of Pyramid's :term:`cookiecutter`\ s include a *transaction
management* system, stolen from Zope.  When you use this transaction management
system, you cease being responsible for committing your data anymore.  Instead
Pyramid takes care of committing: it commits at the end of a request or aborts
if there's an exception.  Why is that a good thing?  Having a centralized place
for transaction management is a great thing.  If, instead of managing your
transactions in a centralized place, you sprinkle ``session.commit`` calls in
your application logic itself, you can wind up in a bad place.  Wherever you
manually commit data to your database, it's likely that some of your other code
is going to run *after* your commit. If that code goes on to do other important
things after that commit, and an error happens in the later code, you can
easily wind up with inconsistent data if you're not extremely careful.  Some
data will have been written to the database that probably should not have.
Having a centralized commit point saves you from needing to think about this;
it's great for lazy people who also care about data integrity.  Either the
request completes successfully, and all changes are committed, or it does not,
and all changes are aborted.
:app:`Pyramid` has been built with a number of other sophisticated design features that make it adaptable. Read more about them below.
Pyramid's transaction management system allows you to synchronize commits
between multiple databases. It also allows you to do things like conditionally
send email if a transaction commits, but otherwise keep quiet.
.. toctree::
   :maxdepth: 2
Example: :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements
anywhere in application code).
Configuration conflict detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a system is small, it's reasonably easy to keep it all in your head. But
when systems grow large, you may have hundreds or thousands of configuration
statements which add a view, add a route, and so forth.
Pyramid's configuration system keeps track of your configuration statements. If
you accidentally add two that are identical, or Pyramid can't make sense out of
what it would mean to have both statements active at the same time, it will
complain loudly at startup time.  It's not dumb though. It will automatically
resolve conflicting configuration statements on its own if you use the
configuration :meth:`~pyramid.config.Configurator.include` system. "More local"
statements are preferred over "less local" ones.  This allows you to
intelligently factor large systems into smaller ones.
Example: :ref:`conflict_detection`.
Configuration extensibility
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlike other systems, Pyramid provides a structured "include" mechanism (see
:meth:`~pyramid.config.Configurator.include`) that allows you to combine
applications from multiple Python packages.  All the configuration statements
that can be performed in your "main" Pyramid application can also be performed
by included packages, including the addition of views, routes, subscribers, and
even authentication and authorization policies. You can even extend or override
an existing application by including another application's configuration in
your own, overriding or adding new views and routes to it.  This has the
potential to allow you to create a big application out of many other smaller
ones.  For example, if you want to reuse an existing application that already
has a bunch of routes, you can just use the ``include`` statement with a
``route_prefix``. The new application will live within your application at an
URL prefix.  It's not a big deal, and requires little up-front engineering
effort.
For example:
.. code-block:: python
   :linenos:
   from pyramid.config import Configurator
   if __name__ == '__main__':
      config = Configurator()
      config.include('pyramid_jinja2')
      config.include('pyramid_exclog')
      config.include('some.other.guys.package', route_prefix='/someotherguy')
.. seealso::
    See also :ref:`including_configuration` and
    :ref:`building_an_extensible_app`.
Flexible authentication and authorization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pyramid includes a flexible, pluggable authentication and authorization system.
No matter where your user data is stored, or what scheme you'd like to use to
permit your users to access your data, you can use a predefined Pyramid
plugpoint to plug in your custom authentication and authorization code.  If you
want to change these schemes later, you can just change it in one place rather
than everywhere in your code.  It also ships with prebuilt well-tested
authentication and authorization schemes out of the box.  But what if you don't
want to use Pyramid's built-in system?  You don't have to. You can just write
your own bespoke security code as you would in any other system.
Example: :ref:`enabling_authorization_policy`.
Traversal
~~~~~~~~~
:term:`Traversal` is a concept stolen from :term:`Zope`.  It allows you to
create a tree of resources, each of which can be addressed by one or more URLs.
Each of those resources can have one or more *views* associated with it. If
your data isn't naturally treelike, or you're unwilling to create a treelike
representation of your data, you aren't going to find traversal very useful.
However, traversal is absolutely fantastic for sites that need to be
arbitrarily extensible. It's a lot easier to add a node to a tree than it is to
shoehorn a route into an ordered list of other routes, or to create another
entire instance of an application to service a department and glue code to
allow disparate apps to share data.  It's a great fit for sites that naturally
lend themselves to changing departmental hierarchies, such as content
management systems and document management systems.  Traversal also lends
itself well to systems that require very granular security ("Bob can edit
*this* document" as opposed to "Bob can edit documents").
Examples: :ref:`hello_traversal_chapter` and
:ref:`much_ado_about_traversal_chapter`.
Tweens
~~~~~~
Pyramid has a sort of internal WSGI-middleware-ish pipeline that can be hooked
by arbitrary add-ons named "tweens".  The debug toolbar is a "tween", and the
``pyramid_tm`` transaction manager is also.  Tweens are more useful than WSGI
:term:`middleware` in some circumstances because they run in the context of
Pyramid itself, meaning you have access to templates and other renderers, a
"real" request object, and other niceties.
Example: :ref:`registering_tweens`.
View response adapters
~~~~~~~~~~~~~~~~~~~~~~
A lot is made of the aesthetics of what *kinds* of objects you're allowed to
return from view callables in various frameworks.  In a previous section in
this document, we showed you that, if you use a :term:`renderer`, you can
usually return a dictionary from a view callable instead of a full-on
:term:`Response` object.  But some frameworks allow you to return strings or
tuples from view callables.  When frameworks allow for this, code looks
slightly prettier, because fewer imports need to be done, and there is less
code.  For example, compare this:
.. code-block:: python
   :linenos:
   def aview(request):
       return "Hello world!"
To this:
.. code-block:: python
   :linenos:
   from pyramid.response import Response
   def aview(request):
       return Response("Hello world!")
The former is "prettier", right?
Out of the box, if you define the former view callable (the one that simply
returns a string) in Pyramid, when it is executed, Pyramid will raise an
exception.  This is because "explicit is better than implicit", in most cases,
and by default Pyramid wants you to return a :term:`Response` object from a
view callable.  This is because there's usually a heck of a lot more to a
response object than just its body.  But if you're the kind of person who
values such aesthetics, we have an easy way to allow for this sort of thing:
.. code-block:: python
   :linenos:
   from pyramid.config import Configurator
   from pyramid.response import Response
   def string_response_adapter(s):
       response = Response(s)
       response.content_type = 'text/html'
       return response
   if __name__ == '__main__':
       config = Configurator()
       config.add_response_adapter(string_response_adapter, basestring)
Do that once in your Pyramid application at startup.  Now you can return
strings from any of your view callables, e.g.:
.. code-block:: python
   :linenos:
   def helloview(request):
       return "Hello world!"
   def goodbyeview(request):
       return "Goodbye world!"
Oh noes!  What if you want to indicate a custom content type?  And a custom
status code?  No fear:
.. code-block:: python
   :linenos:
   from pyramid.config import Configurator
   def tuple_response_adapter(val):
       status_int, content_type, body = val
       response = Response(body)
       response.content_type = content_type
       response.status_int = status_int
       return response
   def string_response_adapter(body):
       response = Response(body)
       response.content_type = 'text/html'
       response.status_int = 200
       return response
   if __name__ == '__main__':
       config = Configurator()
       config.add_response_adapter(string_response_adapter, basestring)
       config.add_response_adapter(tuple_response_adapter, tuple)
Once this is done, both of these view callables will work:
.. code-block:: python
   :linenos:
   def aview(request):
       return "Hello world!"
   def anotherview(request):
       return (403, 'text/plain', "Forbidden")
Pyramid defaults to explicit behavior, because it's the most generally useful,
but provides hooks that allow you to adapt the framework to localized aesthetic
desires.
.. seealso::
    See also :ref:`using_iresponse`.
"Global" response object
~~~~~~~~~~~~~~~~~~~~~~~~
"Constructing these response objects in my view callables is such a chore! And
I'm way too lazy to register a response adapter, as per the prior section," you
say.  Fine.  Be that way:
.. code-block:: python
   :linenos:
   def aview(request):
       response = request.response
       response.body = 'Hello world!'
       response.content_type = 'text/plain'
       return response
.. seealso::
    See also :ref:`request_response_attr`.
Automating repetitive configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Does Pyramid's configurator allow you to do something, but you're a little
adventurous and just want it a little less verbose?  Or you'd like to offer up
some handy configuration feature to other Pyramid users without requiring that
we change Pyramid?  You can extend Pyramid's :term:`Configurator` with your own
directives.  For example, let's say you find yourself calling
:meth:`pyramid.config.Configurator.add_view` repetitively.  Usually you can
take the boring away by using existing shortcuts, but let's say that this is a
case where there is no such shortcut:
.. code-block:: python
   :linenos:
   from pyramid.config import Configurator
   config = Configurator()
   config.add_route('xhr_route', '/xhr/{id}')
   config.add_view('my.package.GET_view', route_name='xhr_route',
                   xhr=True,  permission='view', request_method='GET')
   config.add_view('my.package.POST_view', route_name='xhr_route',
                   xhr=True, permission='view', request_method='POST')
   config.add_view('my.package.HEAD_view', route_name='xhr_route',
                   xhr=True, permission='view', request_method='HEAD')
Pretty tedious right?  You can add a directive to the Pyramid configurator to
automate some of the tedium away:
.. code-block:: python
   :linenos:
   from pyramid.config import Configurator
   def add_protected_xhr_views(config, module):
       module = config.maybe_dotted(module)
       for method in ('GET', 'POST', 'HEAD'):
           view = getattr(module, 'xhr_%s_view' % method, None)
           if view is not None:
               config.add_view(view, route_name='xhr_route', xhr=True,
                              permission='view', request_method=method)
   config = Configurator()
   config.add_directive('add_protected_xhr_views', add_protected_xhr_views)
Once that's done, you can call the directive you've just added as a method of
the Configurator object:
.. code-block:: python
   :linenos:
   config.add_route('xhr_route', '/xhr/{id}')
   config.add_protected_xhr_views('my.package')
Your previously repetitive configuration lines have now morphed into one line.
You can share your configuration code with others this way, too, by packaging
it up and calling :meth:`~pyramid.config.Configurator.add_directive` from
within a function called when another user uses the
:meth:`~pyramid.config.Configurator.include` method against your code.
.. seealso::
    See also :ref:`add_directive`.
Programmatic introspection
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're building a large system that other users may plug code into, it's
useful to be able to get an enumeration of what code they plugged in *at
application runtime*.  For example, you might want to show them a set of tabs
at the top of the screen based on an enumeration of views they registered.
This is possible using Pyramid's :term:`introspector`.
Here's an example of using Pyramid's introspector from within a view callable:
.. code-block:: python
    :linenos:
    from pyramid.view import view_config
    from pyramid.response import Response
    @view_config(route_name='bar')
    def show_current_route_pattern(request):
        introspector = request.registry.introspector
        route_name = request.matched_route.name
        route_intr = introspector.get('routes', route_name)
        return Response(str(route_intr['pattern']))
.. seealso::
    See also :ref:`using_introspection`.
Python 3 compatibility
~~~~~~~~~~~~~~~~~~~~~~
Pyramid and most of its add-ons are Python 3 compatible.  If you develop a
Pyramid application today, you won't need to worry that five years from now
you'll be backwatered because there are language features you'd like to use but
your framework doesn't support newer Python versions.
Testing
~~~~~~~
Every release of Pyramid has 100% statement coverage via unit and integration
tests, as measured by the ``coverage`` tool available on PyPI.  It also has
greater than 95% decision/condition coverage as measured by the
``instrumental`` tool available on PyPI. It is automatically tested by Travis,
and Jenkins on Python 2.7, Python 3.4, Python 3.5, Python 3.6, and PyPy
after each commit to its GitHub repository. Official Pyramid add-ons are held
to a similar testing standard.  We still find bugs in Pyramid and its official
add-ons, but we've noticed we find a lot more of them while working on other
projects that don't have a good testing regime.
Travis: https://travis-ci.org/Pylons/pyramid
Jenkins: http://jenkins.pylonsproject.org/job/pyramid/
Support
~~~~~~~
It's our goal that no Pyramid question go unanswered.  Whether you ask a
question on IRC, on the Pylons-discuss mailing list, or on StackOverflow,
you're likely to get a reasonably prompt response.  We don't tolerate "support
trolls" or other people who seem to get their rocks off by berating fellow
users in our various official support channels.  We try to keep it well-lit and
new-user-friendly.
   advanced-features
Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on
irc.freenode.net in an IRC client) or the pylons-discuss maillist at
https://groups.google.com/forum/#!forum/pylons-discuss.
Documentation
~~~~~~~~~~~~~
It's a constant struggle, but we try to maintain a balance between completeness
and new-user-friendliness in the official narrative Pyramid documentation
(concrete suggestions for improvement are always appreciated, by the way).  We
also maintain a "cookbook" of recipes, which are usually demonstrations of
common integration scenarios too specific to add to the official narrative
docs.  In any case, the Pyramid documentation is comprehensive.
Example: The :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>`.
.. index::
   single: Pylons Project
@@ -901,10 +364,7 @@
What Is The Pylons Project?
---------------------------
:app:`Pyramid` is a member of the collection of software published under the
Pylons Project.  Pylons software is written by a loose-knit community of
contributors.  The `Pylons Project website <http://www.pylonsproject.org>`_
includes details about how :app:`Pyramid` relates to the Pylons Project.
:app:`Pyramid` is a member of the collection of software published under the Pylons Project.  Pylons software is written by a loose-knit community of contributors.  The `Pylons Project website <https://pylonsproject.org>`_ includes details about how :app:`Pyramid` relates to the Pylons Project.
.. index::
   single: pyramid and other frameworks
@@ -914,72 +374,16 @@
   single: MVC
:app:`Pyramid` and Other Web Frameworks
------------------------------------------
---------------------------------------
The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made
in July of 2008.  At the end of 2010, we changed the name of :mod:`repoze.bfg`
to :app:`Pyramid`.  It was merged into the Pylons project as :app:`Pyramid` in
November of that year.
The first release of :app:`Pyramid`\ 's predecessor (named :mod:`repoze.bfg`) was made in July of 2008.  At the end of 2010, we changed the name of :mod:`repoze.bfg` to :app:`Pyramid`.  It was merged into the Pylons project as :app:`Pyramid` in November of that year.
:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version 1.0), and
:term:`Django`.  As a result, :app:`Pyramid` borrows several concepts and
features from each, combining them into a unique web framework.
:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version 1.0), and :term:`Django`.  As a result, :app:`Pyramid` borrows several concepts and features from each, combining them into a unique web framework.
Many features of :app:`Pyramid` trace their origins back to :term:`Zope`. Like
Zope applications, :app:`Pyramid` applications can be easily extended. If you
obey certain constraints, the application you produce can be reused, modified,
re-integrated, or extended by third-party developers without forking the
original application.  The concepts of :term:`traversal` and declarative
security in :app:`Pyramid` were pioneered first in Zope.
Similar to :term:`Zope`, :app:`Pyramid` applications may easily be extended. If you work within the constraints of the framework, you can produce applications that can be reused, modified, or extended without needing to modify the original application code. :app:`Pyramid` also inherits the concepts of :term:`traversal` and declarative security from Zope.
The :app:`Pyramid` concept of :term:`URL dispatch` is inspired by the
:term:`Routes` system used by :term:`Pylons` version 1.0.  Like Pylons version
1.0, :app:`Pyramid` is mostly policy-free.  It makes no assertions about which
database you should use. Pyramid no longer has built-in templating facilities
as of version 1.5a2, but instead officially supports bindings for templating
languages, including Chameleon, Jinja2, and Mako.  In essence, it only supplies
a mechanism to map URLs to :term:`view` code, along with a set of conventions
for calling those views.  You are free to use third-party components that fit
your needs in your applications.
Similar to :term:`Pylons` version 1.0, :app:`Pyramid` is largely free of policy. It makes no assertions about which database or template system you should use. You are free to use whatever third-party components fit the needs of your specific application. :app:`Pyramid` also inherits its approach to :term:`URL dispatch` from Pylons.
The concept of :term:`view` is used by :app:`Pyramid` mostly as it would be by
Django.  :app:`Pyramid` has a documentation culture more like Django's than
like Zope's.
Similar to :term:`Django`, :app:`Pyramid` values extensive documentation. In addition, the concept of a :term:`view` is used by :app:`Pyramid` much as it would be by Django.
Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a :app:`Pyramid`
application developer may use completely imperative code to perform common
framework configuration tasks such as adding a view or a route.  In Zope,
:term:`ZCML` is typically required for similar purposes.  In :term:`Grok`, a
Zope-based web framework, :term:`decorator` objects and class-level
declarations are used for this purpose.  Out of the box, Pyramid supports
imperative and decorator-based configuration. :term:`ZCML` may be used via an
add-on package named ``pyramid_zcml``.
Also unlike :term:`Zope` and other "full-stack" frameworks such as
:term:`Django`, :app:`Pyramid` makes no assumptions about which persistence
mechanisms you should use to build an application.  Zope applications are
typically reliant on :term:`ZODB`. :app:`Pyramid` allows you to build
:term:`ZODB` applications, but it has no reliance on the ZODB software.
Likewise, :term:`Django` tends to assume that you want to store your
application's data in a relational database. :app:`Pyramid` makes no such
assumption, allowing you to use a relational database, and neither encouraging
nor discouraging the decision.
Other Python web frameworks advertise themselves as members of a class of web
frameworks named `model-view-controller
<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_
frameworks. Insofar as this term has been claimed to represent a class of web
frameworks, :app:`Pyramid` also generally fits into this class.
.. sidebar:: You Say :app:`Pyramid` is MVC, but Where's the Controller?
   The :app:`Pyramid` authors believe that the MVC pattern just doesn't really
   fit the web very well. In a :app:`Pyramid` application, there is a resource
   tree which represents the site structure, and views which tend to present
   the data stored in the resource tree and a user-defined "domain model".
   However, no facility provided *by the framework* actually necessarily maps
   to the concept of a "controller" or "model".  So if you had to give it some
   acronym, I guess you'd say :app:`Pyramid` is actually an "RV" framework
   rather than an "MVC" framework.  "MVC", however, is close enough as a
   general classification moniker for purposes of comparison with other web
   frameworks.
Other Python web frameworks advertise themselves as members of a class of web frameworks named `model-view-controller <https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_ frameworks. The authors of :app:`Pyramid` do not believe that the MVC pattern fits the web particularly well. However, if this abstraction works for you, :app:`Pyramid` also generally fits into this class.
docs/narr/myproject/development.ini
@@ -24,7 +24,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/narr/myproject/myproject/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/narr/myproject/setup.py
@@ -9,6 +9,7 @@
    CHANGES = f.read()
requires = [
    'plaster_pastedeploy',
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
docs/narr/project.rst
@@ -85,7 +85,7 @@
.. code-block:: bash
   $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter
   $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -332,7 +332,7 @@
Pyramid will be able to access your Pyramid application.  However, if you want
to open access to other machines on the same network, then edit the
``development.ini`` file, and replace the ``listen`` value in the
``[server:main]`` section, changing it from ``127.0.0.1:6543 [::1]:6543`` to ``*:6543``
``[server:main]`` section, changing it from ``localhost:6543`` to ``*:6543``
(this is equivalent to ``0.0.0.0:6543 [::]:6543``).  For example:
.. code-block:: ini
@@ -356,8 +356,8 @@
You can change the port on which the server runs on by changing the same
portion of the ``development.ini`` file.  For example, you can change the
``listen = 127.0.0.1:6543 [::1]:6543`` line in the ``development.ini`` file's ``[server:main]``
section to ``listen = 127:0.0.1:8080 [::1]:8080`` to run the server on port 8080 instead of port 6543.
``listen = localhost:6543`` line in the ``development.ini`` file's ``[server:main]``
section to ``listen = localhost:8080`` to run the server on port 8080 instead of port 6543.
You can shut down a server started this way by pressing ``Ctrl-C`` (or
``Ctrl-Break`` on Windows).
docs/narr/startup.rst
@@ -10,12 +10,12 @@
    $ $VENV/bin/pserve development.ini
    Starting server in PID 16305.
    Serving on http://127.0.0.1:6543
    Serving on http://[::1]:6543
    Serving on http://localhost:6543
    Serving on http://localhost:6543
This chapter explains what happens between the time you press the "Return" key
on your keyboard after typing ``pserve development.ini`` and the time the line
``serving on http://127.0.0.1:6543`` is output to your console.
on your keyboard after typing ``pserve development.ini`` and the time the lines
``Serving on http://localhost:6543`` are output to your console.
.. index::
   single: startup process
@@ -139,8 +139,8 @@
#. ``pserve`` starts the WSGI *server* defined within the ``[server:main]``
   section.  In our case, this is the Waitress server (``use =
   egg:waitress#main``), and it will listen on all interfaces on port 6543
   for both IPv4 and IPv6 (``listen = 127.0.0.1:6543 [::1]:6543``). The server
   code itself is what prints ``serving on http://127.0.0.1:6543``. The server
   for both IPv4 and IPv6 (``listen = localhost:6543``). The server
   code itself is what prints ``Serving on http://localhost:6543``. The server
   serves the application, and the application is running, waiting to receive requests.
.. seealso::
docs/narr/testing.rst
@@ -376,18 +376,16 @@
.. literalinclude:: myproject/setup.py
    :language: python
    :linenos:
    :lines: 11-22
    :lineno-start: 11
    :emphasize-lines: 8-
    :lines: 11-23
    :lineno-match:
    :emphasize-lines: 9-
Remember to change the dependency.
.. literalinclude:: myproject/setup.py
    :language: python
    :linenos:
    :lines: 40-44
    :lineno-start: 40
    :lines: 42-46
    :lineno-match:
    :emphasize-lines: 2-4
As always, whenever you change your dependencies, make sure to run the correct
docs/quick_tour.rst
@@ -46,7 +46,7 @@
    # set an environment variable to where you want your virtual environment
    c:\\> set VENV=c:\\env
    # create the virtual environment
    c:\\> %VENV%\\Scripts\\python -m venv %VENV%
    c:\\> python -m venv %VENV%
    # install pyramid
    c:\\> %VENV%\\Scripts\\pip install pyramid
    # or for a specific released version
@@ -510,7 +510,7 @@
.. code-block:: bash
    $ $VENV/bin/cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter
    $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -618,7 +618,7 @@
#. *Choice of web server:* ``use = egg:waitress#main`` tells ``pserve`` to
   use the ``waitress`` server.
#. *Interfaces:* ``listen = 127.0.0.1:6543 [::1]:6543`` tells ``waitress`` to listen on all interfaces on port 6543 for both IPv4 and IPv6.
#. *Interfaces:* ``listen = localhost:6543`` tells ``waitress`` to listen on all interfaces on port 6543 for both IPv4 and IPv6.
Additionally the ``development.ini`` generated by this cookiecutter wired up
Python's standard logging. We'll now see in the console, for example, a log on
@@ -647,8 +647,8 @@
.. literalinclude:: quick_tour/package/setup.py
    :language: python
    :lineno-match:
    :lines: 11-16
    :emphasize-lines: 4
    :lines: 11-17
    :emphasize-lines: 5
It was installed when you previously ran:
@@ -657,14 +657,7 @@
    $ $VENV/bin/pip install -e ".[testing]"
The ``pyramid_debugtoolbar`` package is a Pyramid add-on, which means we need
to include its configuration into our web application. The cookiecutter already took care of this for us in its ``__init__.py``:
.. literalinclude:: quick_tour/package/hello_world/__init__.py
    :language: python
    :lineno-match:
    :lines: 8
And it uses the ``pyramid.includes`` facility in our ``development.ini``:
to include its configuration into our web application. The cookiecutter already took care of this for us in its ``development.ini`` using the ``pyramid.includes`` facility:
.. literalinclude:: quick_tour/package/development.ini
    :language: ini
@@ -692,18 +685,17 @@
Our ``pyramid-cookiecutter-starter`` cookiecutter generated a ``tests.py`` module with
one unit test and one functional test in it. It also configured ``setup.py`` with test requirements:
``py.test`` as the test runner, ``WebTest`` for running view tests, and the
``pytest-cov`` tool which yells at us for code that isn't tested. The
highlighted lines show this:
``pytest-cov`` tool which yells at us for code that isn't tested:
.. literalinclude:: quick_tour/package/setup.py
    :language: python
    :lineno-match:
    :lines: 18-22
    :lines: 19-23
.. literalinclude:: quick_tour/package/setup.py
    :language: python
    :lineno-match:
    :lines: 42-44
    :lines: 43-45
We already installed the test requirements when we ran the command ``$VENV/bin/pip install -e ".[testing]"``. We can now run all our tests:
@@ -866,7 +858,7 @@
.. code-block:: bash
    $ cd ~
    $ env/bin/cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy
    $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch
If prompted for the first item, accept the default ``yes`` by hitting return.
docs/quick_tour/logging/development.ini
@@ -24,7 +24,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/quick_tour/logging/hello_world/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/quick_tour/logging/setup.py
@@ -9,6 +9,7 @@
    CHANGES = f.read()
requires = [
    'plaster_pastedeploy',
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
docs/quick_tour/package/development.ini
@@ -24,7 +24,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/quick_tour/package/hello_world/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/quick_tour/package/setup.py
@@ -9,6 +9,7 @@
    CHANGES = f.read()
requires = [
    'plaster_pastedeploy',
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
docs/quick_tour/sessions/development.ini
@@ -24,7 +24,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/quick_tour/sessions/hello_world/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/quick_tour/sessions/setup.py
@@ -9,6 +9,7 @@
    CHANGES = f.read()
requires = [
    'plaster_pastedeploy',
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
docs/quick_tour/sqla_demo/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/sqla_demo.sqlite
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/quick_tour/sqla_demo/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/sqla_demo.sqlite
retry.attempts = 3
###
# wsgi server configuration
###
docs/quick_tour/sqla_demo/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/quick_tour/sqla_demo/sqla_demo/models/__init__.py
@@ -57,10 +57,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/quick_tour/sqla_demo/sqla_demo/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/quick_tutorial/cookiecutters.rst
@@ -28,7 +28,7 @@
    .. code-block:: bash
        $ $VENV/bin/cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter
        $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch
    If prompted for the first item, accept the default ``yes`` by hitting return.
docs/quick_tutorial/cookiecutters/cc_starter/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/quick_tutorial/cookiecutters/development.ini
@@ -24,7 +24,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/quick_tutorial/unit_testing.rst
@@ -29,7 +29,7 @@
convenient than changing to your browser constantly and clicking reload.
We'll also leave discussion of `pytest-cov
<http://pytest-cov.readthedocs.org/en/latest/>`_ for another section.
<http://pytest-cov.readthedocs.io/en/latest/>`_ for another section.
Objectives
docs/tutorials/modwsgi/index.rst
@@ -39,7 +39,7 @@
    .. code-block:: bash
       $ cd ~
       $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter
       $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout 1.9-branch
    If prompted for the first item, accept the default ``yes`` by hitting return.
docs/tutorials/wiki/authorization.rst
@@ -49,7 +49,7 @@
.. literalinclude:: src/authorization/setup.py
   :linenos:
   :emphasize-lines: 21
   :emphasize-lines: 23
   :language: python
Only the highlighted line needs to be added.
@@ -155,9 +155,9 @@
Now add those policies to the configuration:
.. literalinclude:: src/authorization/tutorial/__init__.py
   :lines: 18-23
   :lines: 18-25
   :lineno-match:
   :emphasize-lines: 1-3,5-6
   :emphasize-lines: 1-3,7-8
   :language: python
Only the highlighted lines need to be added.
@@ -233,7 +233,7 @@
.. literalinclude:: src/authorization/tutorial/views.py
   :lines: 6-17
   :emphasize-lines: 1-14
   :emphasize-lines: 1-12
   :language: python
All the highlighted lines need to be added or edited.
@@ -327,7 +327,7 @@
.. literalinclude:: src/authorization/tutorial/__init__.py
   :linenos:
   :emphasize-lines: 4-5,8,18-20,22-23
   :emphasize-lines: 4-5,8,18-20,24-25
   :language: python
Only the highlighted lines need to be added or edited.
docs/tutorials/wiki/basiclayout.rst
@@ -41,14 +41,18 @@
   factory and the settings keywords parsed by :term:`PasteDeploy`.  The root
   factory is named ``root_factory``.
#. *Line 15*.  Include support for the :term:`Chameleon` template rendering
#. *Lines 15 and 16*.  Get the settings and use an explicit transaction transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle.
#. *Line 17*.  Include support for the :term:`Chameleon` template rendering
   bindings, allowing us to use the ``.pt`` templates.
#. *Line 16*.  Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.python.org/pypi/transaction>`_ package.
#. *Line 18*.  Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.python.org/pypi/transaction>`_ package.
#. *Line 17*.  Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application.
#. *Line 19*.  Include support for ``pyramid_retry`` to retry a request when transient exceptions occur.
#. *Line 18*.  Register a "static view", which answers requests whose URL
#. *Line 20*.  Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application.
#. *Line 21*.  Register a "static view", which answers requests whose URL
   paths start with ``/static``, using the
   :meth:`pyramid.config.Configurator.add_static_view` method.  This
   statement registers a view that will serve up static assets, such as CSS
docs/tutorials/wiki/definingviews.rst
@@ -47,7 +47,7 @@
.. literalinclude:: src/views/setup.py
   :linenos:
   :emphasize-lines: 20
   :emphasize-lines: 22
   :language: python
Only the highlighted line needs to be added.
docs/tutorials/wiki/installation.rst
@@ -31,7 +31,7 @@
.. code-block:: bash
    $ cd ~
    $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-zodb
    $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout 1.9-branch
On Windows
^^^^^^^^^^
@@ -39,7 +39,7 @@
.. code-block:: doscon
    c:\> cd \
    c:\> cookiecutter https://github.com/Pylons/pyramid-cookiecutter-zodb
    c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout 1.9-branch
On all operating systems
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -180,12 +180,12 @@
.. literalinclude:: src/installation/setup.py
    :language: python
    :lineno-match:
    :lines: 22-26
    :lines: 24-28
.. literalinclude:: src/installation/setup.py
    :language: python
    :lineno-match:
    :lines: 46-48
    :lines: 48-50
.. _running_tests:
docs/tutorials/wiki/src/authorization/development.ini
@@ -16,6 +16,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki/src/authorization/production.ini
@@ -14,6 +14,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki/src/authorization/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_retry',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
docs/tutorials/wiki/src/authorization/tutorial/__init__.py
@@ -19,10 +19,13 @@
        'sosecret', callback=groupfinder, hashalg='sha512')
    authz_policy = ACLAuthorizationPolicy()
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.set_authentication_policy(authn_policy)
    config.set_authorization_policy(authz_policy)
    config.include('pyramid_chameleon')
    config.include('pyramid_tm')
    config.include('pyramid_retry')
    config.include('pyramid_zodbconn')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -67,7 +67,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -69,7 +69,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -67,7 +67,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/basiclayout/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki/src/basiclayout/development.ini
@@ -16,6 +16,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki/src/basiclayout/production.ini
@@ -14,6 +14,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki/src/basiclayout/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_retry',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
@@ -12,8 +12,11 @@
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.include('pyramid_chameleon')
    config.include('pyramid_tm')
    config.include('pyramid_retry')
    config.include('pyramid_zodbconn')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -43,7 +43,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -59,7 +59,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/installation/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki/src/installation/development.ini
@@ -16,6 +16,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki/src/installation/production.ini
@@ -14,6 +14,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki/src/installation/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_retry',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
docs/tutorials/wiki/src/installation/tutorial/__init__.py
@@ -12,8 +12,11 @@
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.include('pyramid_chameleon')
    config.include('pyramid_tm')
    config.include('pyramid_retry')
    config.include('pyramid_zodbconn')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -43,7 +43,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -59,7 +59,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/models/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki/src/models/development.ini
@@ -16,6 +16,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki/src/models/production.ini
@@ -14,6 +14,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki/src/models/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_retry',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
docs/tutorials/wiki/src/models/tutorial/__init__.py
@@ -12,8 +12,11 @@
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.include('pyramid_chameleon')
    config.include('pyramid_tm')
    config.include('pyramid_retry')
    config.include('pyramid_zodbconn')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -43,7 +43,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -59,7 +59,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/tests/development.ini
@@ -16,6 +16,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki/src/tests/production.ini
@@ -14,6 +14,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki/src/tests/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_retry',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
docs/tutorials/wiki/src/tests/tutorial/__init__.py
@@ -19,10 +19,13 @@
        'sosecret', callback=groupfinder, hashalg='sha512')
    authz_policy = ACLAuthorizationPolicy()
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.set_authentication_policy(authn_policy)
    config.set_authorization_policy(authz_policy)
    config.include('pyramid_chameleon')
    config.include('pyramid_tm')
    config.include('pyramid_retry')
    config.include('pyramid_zodbconn')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -67,7 +67,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/tests/tutorial/templates/login.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -69,7 +69,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/tests/tutorial/templates/mytemplate.pt
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -45,7 +45,7 @@
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -61,7 +61,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/tests/tutorial/templates/view.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -67,7 +67,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/views/development.ini
@@ -16,6 +16,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki/src/views/production.ini
@@ -14,6 +14,8 @@
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki/src/views/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_chameleon',
    'pyramid_debugtoolbar',
    'pyramid_retry',
    'pyramid_tm',
    'pyramid_zodbconn',
    'transaction',
docs/tutorials/wiki/src/views/tutorial/__init__.py
@@ -12,8 +12,11 @@
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.include('pyramid_chameleon')
    config.include('pyramid_tm')
    config.include('pyramid_retry')
    config.include('pyramid_zodbconn')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
docs/tutorials/wiki/src/views/tutorial/templates/edit.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
  <body>
@@ -63,7 +63,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki/src/views/tutorial/templates/view.pt
@@ -19,8 +19,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -64,7 +64,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/authentication.rst
@@ -92,7 +92,7 @@
the file ``development.ini`` and add the highlighted line below:
.. literalinclude:: src/authentication/development.ini
   :lines: 17-19
   :lines: 19-21
   :emphasize-lines: 3
   :lineno-match:
   :language: ini
@@ -101,7 +101,7 @@
open ``production.ini`` and add a different secret:
.. literalinclude:: src/authentication/production.ini
   :lines: 15-17
   :lines: 17-19
   :emphasize-lines: 3
   :lineno-match:
   :language: ini
docs/tutorials/wiki2/installation.rst
@@ -43,7 +43,7 @@
.. code-block:: bash
    $ cd ~
    $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy
    $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch
On Windows
^^^^^^^^^^
@@ -51,7 +51,7 @@
.. code-block:: doscon
    c:\> cd \
    c:\> cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy
    c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout 1.9-branch
On all operating systems
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -190,12 +190,12 @@
.. literalinclude:: src/installation/setup.py
   :language: python
   :lineno-match:
   :lines: 22-26
   :lines: 24-28
.. literalinclude:: src/installation/setup.py
   :language: python
   :lineno-match:
   :lines: 46-48
   :lines: 48-50
.. _sql_running_tests:
docs/tutorials/wiki2/src/authentication/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/authentication/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
auth.secret = seekrit
# By default, the toolbar only appears for clients from IP addresses
@@ -28,7 +30,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/authentication/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
auth.secret = real-seekrit
###
docs/tutorials/wiki2/src/authentication/setup.py
@@ -11,9 +11,11 @@
requires = [
    'bcrypt',
    'docutils',
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/authentication/tutorial/models/__init__.py
@@ -58,10 +58,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/authentication/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/src/authorization/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/authorization/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
auth.secret = seekrit
# By default, the toolbar only appears for clients from IP addresses
@@ -28,7 +30,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/authorization/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
auth.secret = real-seekrit
###
docs/tutorials/wiki2/src/authorization/setup.py
@@ -11,9 +11,11 @@
requires = [
    'bcrypt',
    'docutils',
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/authorization/tutorial/models/__init__.py
@@ -58,10 +58,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/authorization/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/src/basiclayout/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/basiclayout/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki2/src/basiclayout/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py
@@ -57,10 +57,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/src/installation/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/installation/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/installation/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki2/src/installation/setup.py
@@ -9,9 +9,11 @@
    CHANGES = f.read()
requires = [
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py
@@ -57,10 +57,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/src/models/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/models/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/models/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki2/src/models/setup.py
@@ -10,9 +10,11 @@
requires = [
    'bcrypt',
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/models/tutorial/models/__init__.py
@@ -58,10 +58,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -42,7 +42,7 @@
            <ul>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/src/tests/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/tests/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
auth.secret = seekrit
# By default, the toolbar only appears for clients from IP addresses
@@ -28,7 +30,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/tests/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
auth.secret = real-seekrit
###
docs/tutorials/wiki2/src/tests/setup.py
@@ -11,9 +11,11 @@
requires = [
    'bcrypt',
    'docutils',
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/tests/tutorial/models/__init__.py
@@ -58,10 +58,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/tests/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -58,7 +58,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/tutorials/wiki2/src/views/README.txt
@@ -14,7 +14,7 @@
- Upgrade packaging tools.
    env/bin/pip install --upgrade pip setuptools wheel
    env/bin/pip install --upgrade pip setuptools
- Install the project in editable mode with its testing requirements.
docs/tutorials/wiki2/src/views/development.ini
@@ -16,6 +16,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
@@ -26,7 +28,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
docs/tutorials/wiki2/src/views/production.ini
@@ -14,6 +14,8 @@
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
retry.attempts = 3
###
# wsgi server configuration
###
docs/tutorials/wiki2/src/views/setup.py
@@ -11,9 +11,11 @@
requires = [
    'bcrypt',
    'docutils',
    'pyramid',
    'pyramid_jinja2',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
docs/tutorials/wiki2/src/views/tutorial/models/__init__.py
@@ -58,10 +58,14 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
    # use pyramid_retry to retry a request when transient exceptions occur
    config.include('pyramid_retry')
    session_factory = get_session_factory(get_engine(settings))
    config.registry['dbsession_factory'] = session_factory
docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -49,7 +49,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
docs/whatsnew-1.9.rst
@@ -35,6 +35,14 @@
- The threadlocals are now available inside any function invoked via :meth:`pyramid.config.Configurator.include`. This means the only config-time code that cannot rely on threadlocals is code executed from non-actions inside the main. This can be alleviated by invoking :meth:`pyramid.config.Configurator.begin` and :meth:`pyramid.config.Configurator.end` appropriately or using the new context manager feature of the configurator. See https://github.com/Pylons/pyramid/pull/2989
- The threadlocals are now available inside exception views invoked via :meth:`pyramid.request.Request.invoke_exception_view` even when the ``request`` argument is overridden. See https://github.com/Pylons/pyramid/pull/3060
- When unsupported predicates are supplied to :meth:`pyramid.config.Configurator.add_view`, :meth:`pyramid.config.Configurator.add_route` and :meth:`pyramid.config.Configurator.add_subscriber` a much more helpful error message is output with a guess as to which predicate was intended. See https://github.com/Pylons/pyramid/pull/3054
- Normalize the permission results to a proper class hierarchy. :class:`pyramid.security.ACLAllowed` is now a subclass of :class:`pyramid.security.Allowed` and :class:`pyramid.security.ACLDenied` is now a subclass of :class:`pyramid.security.Denied`. See https://github.com/Pylons/pyramid/pull/3084
- Add a ``quote_via`` argument to :func:`pyramid.encode.urlencode` to follow the stdlib's version and enable custom quoting functions. See https://github.com/Pylons/pyramid/pull/3088
Deprecations
------------
@@ -49,25 +57,11 @@
Backward Incompatibilities
--------------------------
- ``request.exception`` and ``request.exc_info`` will only be set if the
  response was generated by the EXCVIEW tween. This is to avoid any confusion
  where a response was generated elsewhere in the pipeline and not in
  direct relation to the original exception. If anyone upstream wants to
  catch and render responses for exceptions they should set
  ``request.exception`` and ``request.exc_info`` themselves to indicate
  the exception that was squashed when generating the response.
- ``request.exception`` and ``request.exc_info`` will only be set if the response was generated by the EXCVIEW tween. This is to avoid any confusion where a response was generated elsewhere in the pipeline and not in direct relation to the original exception. If anyone upstream wants to catch and render responses for exceptions they should set ``request.exception`` and ``request.exc_info`` themselves to indicate the exception that was squashed when generating the response.
  Similar behavior occurs with
  :meth:`pyramid.request.Request.invoke_exception_view` in which
  the exception properties are set to reflect the exception if a response
  is successfully generated by the method.
  Similar behavior occurs with :meth:`pyramid.request.Request.invoke_exception_view` in which the exception properties are set to reflect the exception if a response is successfully generated by the method.
  This is a very minor incompatibility. Most tweens right now would give
  priority to the raised exception and ignore ``request.exception``. This
  change just improves and clarifies that bookkeeping by trying to be
  more clear about the relationship between the response and its squashed
  exception. See https://github.com/Pylons/pyramid/pull/3029 and
  https://github.com/Pylons/pyramid/pull/3031
  This is a very minor incompatibility. Most tweens right now would give priority to the raised exception and ignore ``request.exception``. This change just improves and clarifies that bookkeeping by trying to be more clear about the relationship between the response and its squashed exception. See https://github.com/Pylons/pyramid/pull/3029 and https://github.com/Pylons/pyramid/pull/3031
Documentation Enhancements
--------------------------
pyramid/authentication.py
@@ -1084,10 +1084,12 @@
        from pyramid.view import forbidden_view_config
        @forbidden_view_config()
        def basic_challenge(request):
            response = HTTPUnauthorized()
            response.headers.update(forget(request))
            return response
        def forbidden_view(request):
            if request.authenticated_userid is None:
                response = HTTPUnauthorized()
                response.headers.update(forget(request))
                return response
            return HTTPForbidden()
    """
    def __init__(self, check, realm='Realm', debug=False):
        self.check = check
pyramid/config/util.py
@@ -36,7 +36,7 @@
       config.add_view(
           'mypackage.views.my_view',
           route_name='ok',
           route_name='ok',
           request_method=not_('POST')
           )
@@ -69,7 +69,7 @@
        # if the underlying predicate doesnt return a value, it's not really
        # a predicate, it's just something pretending to be a predicate,
        # so dont update the hash
        if val:
        if val:
            val = '!' + val
        return val
@@ -90,7 +90,7 @@
# over = before
class PredicateList(object):
    def __init__(self):
        self.sorter = TopologicalSorter()
        self.last_added = None
@@ -152,7 +152,16 @@
                weights.append(1 << n + 1)
                preds.append(pred)
        if kw:
            raise ConfigurationError('Unknown predicate values: %r' % (kw,))
            from difflib import get_close_matches
            closest = []
            names = [ name for name, _ in ordered ]
            for name in kw:
                closest.extend(get_close_matches(name, names, 3))
            raise ConfigurationError(
                'Unknown predicate values: %r (did you mean %s)'
                % (kw, ','.join(closest))
            )
        # A "order" is computed for the predicate list.  An order is
        # a scoring.
        #
pyramid/encode.py
@@ -14,13 +14,21 @@
        val = str(val).encode('utf-8')
    return _url_quote(val, safe=safe)
def urlencode(query, doseq=True):
# bw compat api (dnr)
def quote_plus(val, safe=''):
    cls = val.__class__
    if cls is text_type:
        val = val.encode('utf-8')
    elif cls is not binary_type:
        val = str(val).encode('utf-8')
    return _quote_plus(val, safe=safe)
def urlencode(query, doseq=True, quote_via=quote_plus):
    """
    An alternate implementation of Python's stdlib `urllib.urlencode
    function <http://docs.python.org/library/urllib.html>`_ which
    accepts unicode keys and values within the ``query``
    dict/sequence; all Unicode keys and values are first converted to
    UTF-8 before being used to compose the query string.
    An alternate implementation of Python's stdlib
    :func:`urllib.parse.urlencode` function which accepts unicode keys and
    values within the ``query`` dict/sequence; all Unicode keys and values are
    first converted to UTF-8 before being used to compose the query string.
    The value of ``query`` must be a sequence of two-tuples
    representing key/value pairs *or* an object (often a dictionary)
@@ -35,12 +43,18 @@
    the ``doseq=True`` mode, no matter what the value of the second
    argument.
    See the Python stdlib documentation for ``urllib.urlencode`` for
    more information.
    Both the key and value are encoded using the ``quote_via`` function which
    by default is using a similar algorithm to :func:`urllib.parse.quote_plus`
    which converts spaces into '+' characters and '/' into '%2F'.
    .. versionchanged:: 1.5
       In a key/value pair, if the value is ``None`` then it will be
       dropped from the resulting output.
    .. versionchanged:: 1.9
       Added the ``quote_via`` argument to allow alternate quoting algorithms
       to be used.
    """
    try:
        # presumed to be a dictionary
@@ -52,28 +66,19 @@
    prefix = ''
    for (k, v) in query:
        k = quote_plus(k)
        k = quote_via(k)
        if is_nonstr_iter(v):
            for x in v:
                x = quote_plus(x)
                x = quote_via(x)
                result += '%s%s=%s' % (prefix, k, x)
                prefix = '&'
        elif v is None:
            result += '%s%s=' % (prefix, k)
        else:
            v = quote_plus(v)
            v = quote_via(v)
            result += '%s%s=%s' % (prefix, k, v)
        prefix = '&'
    return result
# bw compat api (dnr)
def quote_plus(val, safe=''):
    cls = val.__class__
    if cls is text_type:
        val = val.encode('utf-8')
    elif cls is not binary_type:
        val = str(val).encode('utf-8')
    return _quote_plus(val, safe=safe)
pyramid/interfaces.py
@@ -503,8 +503,10 @@
class IAuthorizationPolicy(Interface):
    """ An object representing a Pyramid authorization policy. """
    def permits(context, principals, permission):
        """ Return ``True`` if any of the ``principals`` is allowed the
        ``permission`` in the current ``context``, else return ``False``
        """ Return an instance of :class:`pyramid.security.Allowed` if any
        of the ``principals`` is allowed the ``permission`` in the current
        ``context``, else return an instance of
        :class:`pyramid.security.Denied`.
        """
    def principals_allowed_by_permission(context, permission):
@@ -713,7 +715,7 @@
        The return value should be a :class:`pyramid.interfaces.IResponse`
        object or an exception that will be handled by WSGI middleware.
        The default execution policy simple creates a request and sends it
        The default execution policy simply creates a request and sends it
        through the pipeline:
        .. code-block:: python
pyramid/router.py
@@ -1,3 +1,4 @@
import sys
from zope.interface import (
    implementer,
    providedBy,
@@ -24,6 +25,7 @@
    BeforeTraversal,
    )
from pyramid.compat import reraise
from pyramid.httpexceptions import HTTPNotFound
from pyramid.request import Request
from pyramid.view import _call_view
@@ -190,13 +192,21 @@
        """
        request.registry = self.registry
        request.invoke_subrequest = self.invoke_subrequest
        return self.invoke_request(
            request,
            _use_tweens=use_tweens,
            _apply_extensions=True,
        )
        extensions = self.request_extensions
        if extensions is not None:
            apply_request_extensions(request, extensions=extensions)
        return self.invoke_request(request, _use_tweens=use_tweens)
    def make_request(self, environ):
        """
        Configure a request object for use by the router.
        The request is created using the configured
        :class:`pyramid.interfaces.IRequestFactory` and will have any
        configured request methods / properties added that were set by
        :meth:`pyramid.config.Configurator.add_request_method`.
        """
        request = self.request_factory(environ)
        request.registry = self.registry
        request.invoke_subrequest = self.invoke_subrequest
@@ -205,8 +215,12 @@
            apply_request_extensions(request, extensions=extensions)
        return request
    def invoke_request(self, request,
                       _use_tweens=True, _apply_extensions=False):
    def invoke_request(self, request, _use_tweens=True):
        """
        Execute a request through the request processing pipeline and
        return the generated response.
        """
        registry = self.registry
        has_listeners = self.registry.has_listeners
        notify = self.registry.notify
@@ -222,9 +236,6 @@
        try:
            try:
                extensions = self.request_extensions
                if _apply_extensions and extensions is not None:
                    apply_request_extensions(request, extensions=extensions)
                response = handle_request(request)
                if request.response_callbacks:
@@ -252,7 +263,15 @@
        response = self.execution_policy(environ, self)
        return response(environ, start_response)
def default_execution_policy(environ, router):
    request = router.make_request(environ)
    return router.invoke_request(request)
    try:
        return router.invoke_request(request)
    except Exception:
        exc_info = sys.exc_info()
        try:
            return request.invoke_exception_view(exc_info)
        except HTTPNotFound:
            reraise(*exc_info)
        finally:
            del exc_info  # avoid local ref cycle
pyramid/scaffolds/alchemy/+package+/models/__init__.py_tmpl
@@ -57,6 +57,7 @@
    """
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    # use pyramid_tm to hook the transaction lifecycle to the request
    config.include('pyramid_tm')
pyramid/scaffolds/alchemy/+package+/templates/layout.jinja2_tmpl
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -44,7 +44,7 @@
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/{{pyramid_docs_branch}}/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -60,7 +60,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
pyramid/scaffolds/alchemy/development.ini_tmpl
@@ -26,7 +26,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
pyramid/scaffolds/starter/+package+/templates/layout.jinja2_tmpl
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -44,7 +44,7 @@
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/{{pyramid_docs_branch}}/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -60,7 +60,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
pyramid/scaffolds/starter/development.ini_tmpl
@@ -24,7 +24,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
pyramid/scaffolds/zodb/+package+/__init__.py
@@ -12,6 +12,8 @@
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(root_factory=root_factory, settings=settings)
    settings = config.get_settings()
    settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
    config.include('pyramid_chameleon')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
pyramid/scaffolds/zodb/+package+/templates/mytemplate.pt_tmpl
@@ -18,8 +18,8 @@
    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>
@@ -45,7 +45,7 @@
              <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/{{pyramid_docs_branch}}/">Docs</a></li>
              <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
              <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
              <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
            </ul>
          </div>
        </div>
@@ -61,7 +61,7 @@
    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>
pyramid/scaffolds/zodb/development.ini_tmpl
@@ -29,7 +29,7 @@
[server:main]
use = egg:waitress#main
listen = 127.0.0.1:6543 [::1]:6543
listen = localhost:6543
###
# logging configuration
pyramid/security.py
@@ -21,10 +21,13 @@
class AllPermissionsList(object):
    """ Stand in 'permission list' to represent all permissions """
    def __iter__(self):
        return ()
        return iter(())
    def __contains__(self, other):
        return True
    def __eq__(self, other):
        return isinstance(other, self.__class__)
@@ -242,6 +245,14 @@
class PermitsResult(int):
    def __new__(cls, s, *args):
        """
        Create a new instance.
        :param fmt: A format string explaining the reason for denial.
        :param args: Arguments are stored and used with the format string
                      to generate the ``msg``.
        """
        inst = int.__new__(cls, cls.boolval)
        inst.s = s
        inst.args = args
@@ -249,6 +260,7 @@
    @property
    def msg(self):
        """ A string indicating why the result was generated."""
        return self.s % self.args
    def __str__(self):
@@ -260,24 +272,52 @@
                                                    self.msg)
class Denied(PermitsResult):
    """ An instance of ``Denied`` is returned when a security-related
    """
    An instance of ``Denied`` is returned when a security-related
    API or other :app:`Pyramid` code denies an action unrelated to
    an ACL check.  It evaluates equal to all boolean false types.  It
    has an attribute named ``msg`` describing the circumstances for
    the deny."""
    the deny.
    """
    boolval = 0
class Allowed(PermitsResult):
    """ An instance of ``Allowed`` is returned when a security-related
    """
    An instance of ``Allowed`` is returned when a security-related
    API or other :app:`Pyramid` code allows an action unrelated to
    an ACL check.  It evaluates equal to all boolean true types.  It
    has an attribute named ``msg`` describing the circumstances for
    the allow."""
    the allow.
    """
    boolval = 1
class ACLPermitsResult(int):
class ACLPermitsResult(PermitsResult):
    def __new__(cls, ace, acl, permission, principals, context):
        inst = int.__new__(cls, cls.boolval)
        """
        Create a new instance.
        :param ace: The :term:`ACE` that matched, triggering the result.
        :param acl: The :term:`ACL` containing ``ace``.
        :param permission: The required :term:`permission`.
        :param principals: The list of :term:`principals <principal>` provided.
        :param context: The :term:`context` providing the :term:`lineage`
                        searched.
        """
        fmt = ('%s permission %r via ACE %r in ACL %r on context %r for '
               'principals %r')
        inst = PermitsResult.__new__(
            cls,
            fmt,
            cls.__name__,
            permission,
            ace,
            acl,
            context,
            principals,
        )
        inst.permission = permission
        inst.ace = ace
        inst.acl = acl
@@ -285,44 +325,31 @@
        inst.context = context
        return inst
    @property
    def msg(self):
        s = ('%s permission %r via ACE %r in ACL %r on context %r for '
             'principals %r')
        return s % (self.__class__.__name__,
                    self.permission,
                    self.ace,
                    self.acl,
                    self.context,
                    self.principals)
class ACLDenied(ACLPermitsResult, Denied):
    """
    An instance of ``ACLDenied`` is a specialization of
    :class:`pyramid.security.Denied` that represents that a security check
    made explicitly against ACL was denied.  It evaluates equal to all
    boolean false types.  It also has the following attributes: ``acl``,
    ``ace``, ``permission``, ``principals``, and ``context``.  These
    attributes indicate the security values involved in the request.  Its
    ``__str__`` method prints a summary of these attributes for debugging
    purposes. The same summary is available as the ``msg`` attribute.
    def __str__(self):
        return self.msg
    """
    def __repr__(self):
        return '<%s instance at %s with msg %r>' % (self.__class__.__name__,
                                                    id(self),
                                                    self.msg)
class ACLAllowed(ACLPermitsResult, Allowed):
    """
    An instance of ``ACLAllowed`` is a specialization of
    :class:`pyramid.security.Allowed` that represents that a security check
    made explicitly against ACL was allowed.  It evaluates equal to all
    boolean true types.  It also has the following attributes: ``acl``,
    ``ace``, ``permission``, ``principals``, and ``context``.  These
    attributes indicate the security values involved in the request.  Its
    ``__str__`` method prints a summary of these attributes for debugging
    purposes. The same summary is available as the ``msg`` attribute.
class ACLDenied(ACLPermitsResult):
    """ An instance of ``ACLDenied`` represents that a security check made
    explicitly against ACL was denied.  It evaluates equal to all boolean
    false types.  It also has the following attributes: ``acl``, ``ace``,
    ``permission``, ``principals``, and ``context``.  These attributes
    indicate the security values involved in the request.  Its __str__ method
    prints a summary of these attributes for debugging purposes.  The same
    summary is available as the ``msg`` attribute."""
    boolval = 0
class ACLAllowed(ACLPermitsResult):
    """ An instance of ``ACLAllowed`` represents that a security check made
    explicitly against ACL was allowed.  It evaluates equal to all boolean
    true types.  It also has the following attributes: ``acl``, ``ace``,
    ``permission``, ``principals``, and ``context``.  These attributes
    indicate the security values involved in the request.  Its __str__ method
    prints a summary of these attributes for debugging purposes.  The same
    summary is available as the ``msg`` attribute."""
    boolval = 1
    """
class AuthenticationAPIMixin(object):
@@ -392,7 +419,8 @@
        :type permission: unicode, str
        :param context: A resource object or ``None``
        :type context: object
        :returns: `pyramid.security.PermitsResult`
        :returns: Either :class:`pyramid.security.Allowed` or
                  :class:`pyramid.security.Denied`.
        .. versionadded:: 1.5
pyramid/tests/test_config/test_util.py
@@ -365,6 +365,16 @@
        from pyramid.exceptions import ConfigurationError
        self.assertRaises(ConfigurationError, self._callFUT, unknown=1)
    def test_predicate_close_matches(self):
        from pyramid.exceptions import ConfigurationError
        with  self.assertRaises(ConfigurationError) as context:
            self._callFUT(method='GET')
        expected_msg = (
            "Unknown predicate values: {'method': 'GET'} "
            "(did you mean request_method)"
        )
        self.assertEqual(context.exception.args[0], expected_msg)
    def test_notted(self):
        from pyramid.config import not_
        from pyramid.testing import DummyRequest
pyramid/tests/test_encode.py
@@ -5,9 +5,9 @@
    )
class UrlEncodeTests(unittest.TestCase):
    def _callFUT(self, query, doseq=False):
    def _callFUT(self, query, doseq=False, **kw):
        from pyramid.encode import urlencode
        return urlencode(query, doseq)
        return urlencode(query, doseq, **kw)
    def test_ascii_only(self):
        result = self._callFUT([('a',1), ('b',2)])
@@ -53,6 +53,13 @@
        result = self._callFUT([('a', '1'), ('b', None), ('c', None)])
        self.assertEqual(result, 'a=1&b=&c=')
    def test_quote_via(self):
        def my_quoter(value):
            return 'xxx' + value
        result = self._callFUT([('a', '1'), ('b', None), ('c', None)],
                               quote_via=my_quoter)
        self.assertEqual(result, 'xxxa=xxx1&xxxb=&xxxc=')
class URLQuoteTests(unittest.TestCase):
    def _callFUT(self, val, safe=''):
        from pyramid.encode import url_quote
pyramid/tests/test_router.py
@@ -1284,6 +1284,33 @@
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(resp.body, b'foo')
    def test_execution_policy_handles_exception(self):
        from pyramid.interfaces import IViewClassifier
        from pyramid.interfaces import IExceptionViewClassifier
        from pyramid.interfaces import IRequest
        class Exception1(Exception):
            pass
        class Exception2(Exception):
            pass
        req_iface = self._registerRouteRequest('foo')
        self._connectRoute('foo', 'archives/:action/:article', None)
        view = DummyView(DummyResponse(), raise_exception=Exception1)
        self._registerView(view, '', IViewClassifier, req_iface, None)
        exception_view1 = DummyView(DummyResponse(),
                                    raise_exception=Exception2)
        self._registerView(exception_view1, '', IExceptionViewClassifier,
                           IRequest, Exception1)
        response = DummyResponse()
        response.app_iter = ["Hello, world"]
        exception_view2 = DummyView(response)
        self._registerView(exception_view2, '', IExceptionViewClassifier,
                           IRequest, Exception2)
        environ = self._makeEnviron(PATH_INFO='/archives/action1/article1')
        start_response = DummyStartResponse()
        router = self._makeOne()
        result = router(environ, start_response)
        self.assertEqual(result, ["Hello, world"])
class DummyPredicate(object):
    def __call__(self, info, request):
        return True
pyramid/tests/test_scaffolds/fixture_scaffold/+package+/templates/mytemplate.pt_tmpl
@@ -41,7 +41,7 @@
          <h2>Pyramid links</h2>
          <ul class="links">
            <li>
              <a href="http://pylonsproject.org">Pylons Website</a>
              <a href="https://pylonsproject.org">Pylons Website</a>
            </li>
            <li>
              <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a>
pyramid/tests/test_security.py
@@ -16,11 +16,31 @@
    def _makeOne(self):
        return self._getTargetClass()()
    def test_it(self):
    def test_equality_w_self(self):
        thing = self._makeOne()
        self.assertTrue(thing.__eq__(thing))
        self.assertEqual(thing.__iter__(), ())
    def test_equality_w_other_instances_of_class(self):
        thing = self._makeOne()
        other = self._makeOne()
        self.assertTrue(thing.__eq__(other))
    def test_equality_miss(self):
        thing = self._makeOne()
        other = object()
        self.assertFalse(thing.__eq__(other))
    def test_contains_w_string(self):
        thing = self._makeOne()
        self.assertTrue('anything' in thing)
    def test_contains_w_object(self):
        thing = self._makeOne()
        self.assertTrue(object() in thing)
    def test_iterable(self):
        thing = self._makeOne()
        self.assertEqual(list(thing), [])
    def test_singleton(self):
        from pyramid.security import ALL_PERMISSIONS
@@ -72,9 +92,11 @@
        return klass(*arg, **kw)
    def test_it(self):
        from pyramid.security import Allowed
        msg = ("ACLAllowed permission 'permission' via ACE 'ace' in ACL 'acl' "
               "on context 'ctx' for principals 'principals'")
        allowed = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx')
        self.assertIsInstance(allowed, Allowed)
        self.assertTrue(msg in allowed.msg)
        self.assertEqual(allowed, True)
        self.assertTrue(allowed)
@@ -92,9 +114,11 @@
        return klass(*arg, **kw)
    def test_it(self):
        from pyramid.security import Denied
        msg = ("ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' "
               "on context 'ctx' for principals 'principals'")
        denied = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx')
        self.assertIsInstance(denied, Denied)
        self.assertTrue(msg in denied.msg)
        self.assertEqual(denied, False)
        self.assertFalse(denied)
pyramid/tests/test_view.py
@@ -790,6 +790,8 @@
    def test_it_supports_alternate_requests(self):
        def exc_view(exc, request):
            self.assertTrue(request is other_req)
            from pyramid.threadlocal import get_current_request
            self.assertTrue(get_current_request() is other_req)
            return DummyResponse(b'foo')
        self.config.add_view(exc_view, context=RuntimeError)
        request = self._makeOne()
@@ -815,6 +817,23 @@
            self.assertEqual(response.app_iter, [b'foo'])
        else: # pragma: no cover
            self.fail()
    def test_it_raises_if_no_registry(self):
        request = self._makeOne()
        del request.registry
        from pyramid.threadlocal import manager
        manager.push({'registry': None, 'request': request})
        try:
            raise RuntimeError
        except RuntimeError:
            try:
                request.invoke_exception_view()
            except RuntimeError as e:
                self.assertEqual(e.args[0], "Unable to retrieve registry")
        else: # pragma: no cover
            self.fail()
        finally:
            manager.pop()
    def test_it_supports_alternate_exc_info(self):
        def exc_view(exc, request):
@@ -867,6 +886,18 @@
        else: # pragma: no cover
            self.fail()
    def test_it_reraises_if_not_found(self):
        request = self._makeOne()
        dummy_exc = RuntimeError()
        try:
            raise dummy_exc
        except RuntimeError:
            self.assertRaises(
                RuntimeError,
                lambda: request.invoke_exception_view(reraise=True))
        else: # pragma: no cover
            self.fail()
    def test_it_raises_predicate_mismatch(self):
        from pyramid.exceptions import PredicateMismatch
        def exc_view(exc, request): pass
@@ -881,6 +912,21 @@
        else: # pragma: no cover
            self.fail()
    def test_it_reraises_after_predicate_mismatch(self):
        def exc_view(exc, request): pass
        self.config.add_view(exc_view, context=Exception, request_method='POST')
        request = self._makeOne()
        request.method = 'GET'
        dummy_exc = RuntimeError()
        try:
            raise dummy_exc
        except RuntimeError:
            self.assertRaises(
                RuntimeError,
                lambda: request.invoke_exception_view(reraise=True))
        else: # pragma: no cover
            self.fail()
class ExceptionResponse(Exception):
    status = '404 Not Found'
    app_iter = ['Not Found']
pyramid/threadlocal.py
@@ -31,7 +31,7 @@
        self.stack[:] = []
def defaults():
    return {'request':None, 'registry':global_registry}
    return {'request': None, 'registry': global_registry}
manager = ThreadLocalManager(default=defaults)
pyramid/view.py
@@ -16,6 +16,7 @@
    )
from pyramid.compat import decode_path_info
from pyramid.compat import reraise as reraise_
from pyramid.exceptions import (
    ConfigurationError,
@@ -28,7 +29,11 @@
    default_exceptionresponse_view,
    )
from pyramid.threadlocal import get_current_registry
from pyramid.threadlocal import (
    get_current_registry,
    manager,
    )
from pyramid.util import hide_attrs
_marker = object()
@@ -626,8 +631,9 @@
        self,
        exc_info=None,
        request=None,
        secure=True
        ):
        secure=True,
        reraise=False,
    ):
        """ Executes an exception view related to the request it's called upon.
        The arguments it takes are these:
@@ -650,24 +656,26 @@
            does not have the appropriate permission, this should be ``True``.
            Default: ``True``.
        If called with no arguments, it uses the global exception information
        returned by ``sys.exc_info()`` as ``exc_info``, the request
        object that this method is attached to as the ``request``, and
        ``True`` for ``secure``.
        ``reraise``
        This method returns a :term:`response` object or raises
        :class:`pyramid.httpexceptions.HTTPNotFound` if a matching view cannot
        be found.
            A boolean indicating whether the original error should be reraised
            if a :term:`response` object could not be created. If ``False``
            then an :class:`pyramid.httpexceptions.HTTPNotFound`` exception
            will be raised. Default: ``False``.
        If a response is generated then ``request.exception`` and
        ``request.exc_info`` will be left at the values used to render the
        response. Otherwise the previous values for ``request.exception`` and
        ``request.exc_info`` will be restored.
        .. versionadded:: 1.7
        .. versionchanged:: 1.9
           The ``request.exception`` and ``request.exc_info`` properties will
           reflect the exception used to render the response where previously
           they were reset to the values prior to invoking the method.
           Also added the ``reraise`` argument.
        """
        if request is None:
@@ -675,8 +683,13 @@
        registry = getattr(request, 'registry', None)
        if registry is None:
            registry = get_current_registry()
        if registry is None:
            raise RuntimeError("Unable to retrieve registry")
        if exc_info is None:
            exc_info = sys.exc_info()
        exc = exc_info[1]
        attrs = request.__dict__
        context_iface = providedBy(exc)
@@ -690,19 +703,31 @@
            # we use .get instead of .__getitem__ below due to
            # https://github.com/Pylons/pyramid/issues/700
            request_iface = attrs.get('request_iface', IRequest)
            response = _call_view(
                registry,
                request,
                exc,
                context_iface,
                '',
                view_types=None,
                view_classifier=IExceptionViewClassifier,
                secure=secure,
                request_iface=request_iface.combined,
                )
            manager.push({'request': request, 'registry': registry})
            try:
                response = _call_view(
                    registry,
                    request,
                    exc,
                    context_iface,
                    '',
                    view_types=None,
                    view_classifier=IExceptionViewClassifier,
                    secure=secure,
                    request_iface=request_iface.combined,
                    )
            except:
                if reraise:
                    reraise_(*exc_info)
                raise
            finally:
                manager.pop()
        if response is None:
            if reraise:
                reraise_(*exc_info)
            raise HTTPNotFound
        # successful response, overwrite exception/exc_info
setup.py
@@ -61,7 +61,7 @@
    ]
setup(name='pyramid',
      version='1.9a1',
      version='1.9a2',
      description='The Pyramid Web Framework, a Pylons project',
      long_description=README + '\n\n' + CHANGES,
      classifiers=[