summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/api/session.rst1
-rw-r--r--docs/api/static.rst8
-rw-r--r--docs/conf.py9
-rw-r--r--docs/designdefense.rst191
-rw-r--r--docs/glossary.rst6
-rw-r--r--docs/index.rst164
-rw-r--r--docs/narr/MyProject/development.ini6
-rw-r--r--docs/narr/MyProject/myproject/templates/mytemplate.pt13
-rw-r--r--docs/narr/MyProject/myproject/tests.py25
-rw-r--r--docs/narr/MyProject/production.ini2
-rw-r--r--docs/narr/MyProject/setup.py45
-rw-r--r--docs/narr/advconfig.rst133
-rw-r--r--docs/narr/assets.rst351
-rw-r--r--docs/narr/commandline.rst103
-rw-r--r--docs/narr/extconfig.rst265
-rw-r--r--docs/narr/extending.rst194
-rw-r--r--docs/narr/hellotraversal.rst67
-rw-r--r--docs/narr/hooks.rst644
-rw-r--r--docs/narr/hybrid.rst539
-rw-r--r--docs/narr/introspector.rst123
-rw-r--r--docs/narr/muchadoabouttraversal.rst341
-rw-r--r--docs/narr/project.rst104
-rw-r--r--docs/narr/renderers.rst4
-rw-r--r--docs/narr/resources.rst390
-rw-r--r--docs/narr/scaffolding.rst102
-rw-r--r--docs/narr/security.rst438
-rw-r--r--docs/narr/startup.rst27
-rw-r--r--docs/narr/subrequest.rst156
-rw-r--r--docs/narr/tb_introspector.pngbin95962 -> 181225 bytes
-rw-r--r--docs/narr/testing.rst262
-rw-r--r--docs/narr/threadlocals.rst226
-rw-r--r--docs/narr/traversal.rst425
-rw-r--r--docs/narr/upgrading.rst163
-rw-r--r--docs/narr/zca.rst257
-rw-r--r--docs/pscripts/index.rst12
-rw-r--r--docs/pscripts/pcreate.rst13
-rw-r--r--docs/pscripts/pdistreport.rst13
-rw-r--r--docs/pscripts/prequest.rst13
-rw-r--r--docs/pscripts/proutes.rst13
-rw-r--r--docs/pscripts/pserve.rst13
-rw-r--r--docs/pscripts/pshell.rst13
-rw-r--r--docs/pscripts/ptweens.rst13
-rw-r--r--docs/pscripts/pviews.rst13
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst2
-rw-r--r--docs/whatsnew-1.0.rst2
-rw-r--r--docs/whatsnew-1.1.rst2
-rw-r--r--docs/whatsnew-1.2.rst2
-rw-r--r--docs/whatsnew-1.3.rst2
-rw-r--r--docs/whatsnew-1.4.rst2
-rw-r--r--docs/whatsnew-1.5.rst4
-rw-r--r--docs/whatsnew-1.6.rst204
51 files changed, 3085 insertions, 3035 deletions
diff --git a/docs/api/session.rst b/docs/api/session.rst
index dde9d20e9..474e2bb32 100644
--- a/docs/api/session.rst
+++ b/docs/api/session.rst
@@ -17,4 +17,5 @@
.. autofunction:: BaseCookieSessionFactory
+ .. autoclass:: PickleSerializer
diff --git a/docs/api/static.rst b/docs/api/static.rst
index b6b279139..f3727e197 100644
--- a/docs/api/static.rst
+++ b/docs/api/static.rst
@@ -9,17 +9,11 @@
:members:
:inherited-members:
- .. autoclass:: PathSegmentCacheBuster
+ .. autoclass:: ManifestCacheBuster
:members:
.. autoclass:: QueryStringCacheBuster
:members:
- .. autoclass:: PathSegmentMd5CacheBuster
- :members:
-
- .. autoclass:: QueryStringMd5CacheBuster
- :members:
-
.. autoclass:: QueryStringConstantCacheBuster
:members:
diff --git a/docs/conf.py b/docs/conf.py
index 8a9bac6ed..073811eca 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -53,12 +53,13 @@ extensions = [
'sphinx.ext.doctest',
'repoze.sphinx.autointerface',
'sphinx.ext.viewcode',
- 'sphinx.ext.intersphinx'
+ 'sphinx.ext.intersphinx',
+ 'sphinxcontrib.programoutput',
]
# Looks for objects in external projects
intersphinx_mapping = {
- 'colander': ( 'http://docs.pylonsproject.org/projects/colander/en/latest', None),
+ 'colander': ('http://docs.pylonsproject.org/projects/colander/en/latest', None),
'cookbook': ('http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/', None),
'deform': ('http://docs.pylonsproject.org/projects/deform/en/latest', None),
'jinja2': ('http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/', None),
@@ -66,8 +67,8 @@ intersphinx_mapping = {
'python': ('http://docs.python.org', None),
'python3': ('http://docs.python.org/3', None),
'sqla': ('http://docs.sqlalchemy.org/en/latest', None),
- 'tm': ('http://docs.pylonsproject.org/projects/pyramid_tm/en/latest/', None),
- 'toolbar': ('http://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest', None),
+ 'tm': ('http://docs.pylonsproject.org/projects/pyramid_tm/en/latest/', None),
+ 'toolbar': ('http://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest', None),
'tstring': ('http://docs.pylonsproject.org/projects/translationstring/en/latest', None),
'tutorials': ('http://docs.pylonsproject.org/projects/pyramid-tutorials/en/latest/', None),
'venusian': ('http://docs.pylonsproject.org/projects/venusian/en/latest', None),
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index 1ed4f65a4..bfde25246 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -7,98 +7,94 @@ From time to time, challenges to various aspects of :app:`Pyramid` design are
lodged. To give context to discussions that follow, we detail some of the
design decisions and trade-offs here. In some cases, we acknowledge that the
framework can be made better and we describe future steps which will be taken
-to improve it; in some cases we just file the challenge as noted, as
-obviously you can't please everyone all of the time.
+to improve it. In others we just file the challenge as noted, as obviously you
+can't please everyone all of the time.
Pyramid Provides More Than One Way to Do It
-------------------------------------------
A canon of Python popular culture is "TIOOWTDI" ("there is only one way to do
-it", a slighting, tongue-in-cheek reference to Perl's "TIMTOWTDI", which is
-an acronym for "there is more than one way to do it").
-
-:app:`Pyramid` is, for better or worse, a "TIMTOWTDI" system. For example,
-it includes more than one way to resolve a URL to a :term:`view callable`:
-via :term:`url dispatch` or :term:`traversal`. Multiple methods of
-configuration exist: :term:`imperative configuration`, :term:`configuration
-decoration`, and :term:`ZCML` (optionally via :term:`pyramid_zcml`). It works
-with multiple different kinds of persistence and templating systems. And so
-on. However, the existence of most of these overlapping ways to do things
-are not without reason and purpose: we have a number of audiences to serve,
-and we believe that TIMTOWTI at the web framework level actually *prevents* a
-much more insidious and harmful set of duplication at higher levels in the
-Python web community.
-
-:app:`Pyramid` began its life as :mod:`repoze.bfg`, written by a team of
-people with many years of prior :term:`Zope` experience. The idea of
+it", a slighting, tongue-in-cheek reference to Perl's "TIMTOWTDI", which is an
+acronym for "there is more than one way to do it").
+
+:app:`Pyramid` is, for better or worse, a "TIMTOWTDI" system. For example, it
+includes more than one way to resolve a URL to a :term:`view callable`: via
+:term:`url dispatch` or :term:`traversal`. Multiple methods of configuration
+exist: :term:`imperative configuration`, :term:`configuration decoration`, and
+:term:`ZCML` (optionally via :term:`pyramid_zcml`). It works with multiple
+different kinds of persistence and templating systems. And so on. However, the
+existence of most of these overlapping ways to do things are not without reason
+and purpose: we have a number of audiences to serve, and we believe that
+TIMTOWTDI at the web framework level actually *prevents* a much more insidious
+and harmful set of duplication at higher levels in the Python web community.
+
+:app:`Pyramid` began its life as :mod:`repoze.bfg`, written by a team of people
+with many years of prior :term:`Zope` experience. The idea of
:term:`traversal` and the way :term:`view lookup` works was stolen entirely
from Zope. The authorization subsystem provided by :app:`Pyramid` is a
derivative of Zope's. The idea that an application can be *extended* without
forking is also a Zope derivative.
Implementations of these features were *required* to allow the :app:`Pyramid`
-authors to build the bread-and-butter CMS-type systems for customers in the
-way in which they were accustomed. No other system, save for Zope itself,
-had such features, and Zope itself was beginning to show signs of its age.
-We were becoming hampered by consequences of its early design mistakes.
-Zope's lack of documentation was also difficult to work around: it was hard
-to hire smart people to work on Zope applications, because there was no
-comprehensive documentation set to point them at which explained "it all" in
-one consumable place, and it was too large and self-inconsistent to document
-properly. Before :mod:`repoze.bfg` went under development, its authors
-obviously looked around for other frameworks that fit the bill. But no
-non-Zope framework did. So we embarked on building :mod:`repoze.bfg`.
+authors to build the bread-and-butter CMS-type systems for customers in the way
+in which they were accustomed. No other system, save for Zope itself, had such
+features, and Zope itself was beginning to show signs of its age. We were
+becoming hampered by consequences of its early design mistakes. Zope's lack of
+documentation was also difficult to work around. It was hard to hire smart
+people to work on Zope applications because there was no comprehensive
+documentation set which explained "it all" in one consumable place, and it was
+too large and self-inconsistent to document properly. Before :mod:`repoze.bfg`
+went under development, its authors obviously looked around for other
+frameworks that fit the bill. But no non-Zope framework did. So we embarked on
+building :mod:`repoze.bfg`.
As the result of our research, however, it became apparent that, despite the
-fact that no *one* framework had all the features we required, lots of
-existing frameworks had good, and sometimes very compelling ideas. In
-particular, :term:`URL dispatch` is a more direct mechanism to map URLs to
-code.
+fact that no *one* framework had all the features we required, lots of existing
+frameworks had good, and sometimes very compelling ideas. In particular,
+:term:`URL dispatch` is a more direct mechanism to map URLs to code.
So, although we couldn't find a framework, save for Zope, that fit our needs,
and while we incorporated a lot of Zope ideas into BFG, we also emulated the
features we found compelling in other frameworks (such as :term:`url
-dispatch`). After the initial public release of BFG, as time went on,
-features were added to support people allergic to various Zope-isms in the
-system, such as the ability to configure the application using
-:term:`imperative configuration` and :term:`configuration decoration` rather
-than solely using :term:`ZCML`, and the elimination of the required use of
-:term:`interface` objects. It soon became clear that we had a system that
-was very generic, and was beginning to appeal to non-Zope users as well as
-ex-Zope users.
+dispatch`). After the initial public release of BFG, as time went on, features
+were added to support people allergic to various Zope-isms in the system, such
+as the ability to configure the application using :term:`imperative
+configuration` and :term:`configuration decoration`, rather than solely using
+:term:`ZCML`, and the elimination of the required use of :term:`interface`
+objects. It soon became clear that we had a system that was very generic, and
+was beginning to appeal to non-Zope users as well as ex-Zope users.
As the result of this generalization, it became obvious BFG shared 90% of its
-featureset with the featureset of Pylons 1, and thus had a very similar
-target market. Because they were so similar, choosing between the two
-systems was an exercise in frustration for an otherwise non-partisan
-developer. It was also strange for the Pylons and BFG development
-communities to be in competition for the same set of users, given how similar
-the two frameworks were. So the Pylons and BFG teams began to work together
-to form a plan to merge. The features missing from BFG (notably :term:`view
-handler` classes, flash messaging, and other minor missing bits), were added,
-to provide familiarity to ex-Pylons users. The result is :app:`Pyramid`.
-
-The Python web framework space is currently notoriously balkanized. We're
-truly hoping that the amalgamation of components in :app:`Pyramid` will
-appeal to at least two currently very distinct sets of users: Pylons and BFG
-users. By unifying the best concepts from Pylons and BFG into a single
-codebase and leaving the bad concepts from their ancestors behind, we'll be
-able to consolidate our efforts better, share more code, and promote our
-efforts as a unit rather than competing pointlessly. We hope to be able to
-shortcut the pack mentality which results in a *much larger* duplication of
-effort, represented by competing but incredibly similar applications and
-libraries, each built upon a specific low level stack that is incompatible
-with the other. We'll also shrink the choice of credible Python web
-frameworks down by at least one. We're also hoping to attract users from
-other communities (such as Zope's and TurboGears') by providing the features
-they require, while allowing enough flexibility to do things in a familiar
-fashion. Some overlap of functionality to achieve these goals is expected
-and unavoidable, at least if we aim to prevent pointless duplication at
-higher levels. If we've done our job well enough, the various audiences will
-be able to coexist and cooperate rather than firing at each other across some
-imaginary web framework DMZ.
-
-Pyramid Uses A Zope Component Architecture ("ZCA") Registry
+feature set with the feature set of Pylons 1, and thus had a very similar
+target market. Because they were so similar, choosing between the two systems
+was an exercise in frustration for an otherwise non-partisan developer. It was
+also strange for the Pylons and BFG development communities to be in
+competition for the same set of users, given how similar the two frameworks
+were. So the Pylons and BFG teams began to work together to form a plan to
+merge. The features missing from BFG (notably :term:`view handler` classes,
+flash messaging, and other minor missing bits), were added to provide
+familiarity to ex-Pylons users. The result is :app:`Pyramid`.
+
+The Python web framework space is currently notoriously balkanized. We're truly
+hoping that the amalgamation of components in :app:`Pyramid` will appeal to at
+least two currently very distinct sets of users: Pylons and BFG users. By
+unifying the best concepts from Pylons and BFG into a single codebase, and
+leaving the bad concepts from their ancestors behind, we'll be able to
+consolidate our efforts better, share more code, and promote our efforts as a
+unit rather than competing pointlessly. We hope to be able to shortcut the pack
+mentality which results in a *much larger* duplication of effort, represented
+by competing but incredibly similar applications and libraries, each built upon
+a specific low level stack that is incompatible with the other. We'll also
+shrink the choice of credible Python web frameworks down by at least one. We're
+also hoping to attract users from other communities (such as Zope's and
+TurboGears') by providing the features they require, while allowing enough
+flexibility to do things in a familiar fashion. Some overlap of functionality
+to achieve these goals is expected and unavoidable, at least if we aim to
+prevent pointless duplication at higher levels. If we've done our job well
+enough, the various audiences will be able to coexist and cooperate rather than
+firing at each other across some imaginary web framework DMZ.
+
+Pyramid Uses a Zope Component Architecture ("ZCA") Registry
-----------------------------------------------------------
:app:`Pyramid` uses a :term:`Zope Component Architecture` (ZCA) "component
@@ -146,7 +142,7 @@ dictionary API, but that's not very important in this context. That's
problem number two.
Third of all, what does the ``getUtility`` function do? It's performing a
-lookup for the ``ISettings`` "utility" that should return.. well, a utility.
+lookup for the ``ISettings`` "utility" that should return... well, a utility.
Note how we've already built up a dependency on the understanding of an
:term:`interface` and the concept of "utility" to answer this question: a bad
sign so far. Note also that the answer is circular, a *really* bad sign.
@@ -156,12 +152,12 @@ registry" of course. What's a component registry? Problem number four.
Fifth, assuming you buy that there's some magical registry hanging around,
where *is* this registry? *Homina homina*... "around"? That's sort of the
-best answer in this context (a more specific answer would require knowledge
-of internals). Can there be more than one registry? Yes. So *which*
-registry does it find the registration in? Well, the "current" registry of
-course. In terms of :app:`Pyramid`, the current registry is a thread local
-variable. Using an API that consults a thread local makes understanding how
-it works non-local.
+best answer in this context (a more specific answer would require knowledge of
+internals). Can there be more than one registry? Yes. So in *which* registry
+does it find the registration? Well, the "current" registry of course. In
+terms of :app:`Pyramid`, the current registry is a thread local variable.
+Using an API that consults a thread local makes understanding how it works
+non-local.
You've now bought in to the fact that there's a registry that is just hanging
around. But how does the registry get populated? Why, via code that calls
@@ -170,10 +166,10 @@ registration of ``ISettings`` is made by the framework itself under the hood:
it's not present in any user configuration. This is extremely hard to
comprehend. Problem number six.
-Clearly there's some amount of cognitive load here that needs to be borne by
-a reader of code that extends the :app:`Pyramid` framework due to its use of
-the ZCA, even if he or she is already an expert Python programmer and whom is
-an expert in the domain of web applications. This is suboptimal.
+Clearly there's some amount of cognitive load here that needs to be borne by a
+reader of code that extends the :app:`Pyramid` framework due to its use of the
+ZCA, even if they are already an expert Python programmer and an expert in the
+domain of web applications. This is suboptimal.
Ameliorations
+++++++++++++
@@ -907,23 +903,22 @@ creating a more Zope3-like environment without much effort.
.. _http_exception_hierarchy:
-Pyramid Uses its Own HTTP Exception Class Hierarchy Rather Than ``webob.exc``
------------------------------------------------------------------------------
+Pyramid uses its own HTTP exception class hierarchy rather than :mod:`webob.exc`
+--------------------------------------------------------------------------------
.. versionadded:: 1.1
The HTTP exception classes defined in :mod:`pyramid.httpexceptions` are very
-much like the ones defined in ``webob.exc``
-(e.g. :class:`~pyramid.httpexceptions.HTTPNotFound`,
-:class:`~pyramid.httpexceptions.HTTPForbidden`, etc). They have the same
-names and largely the same behavior and all have a very similar
-implementation, but not the same identity. Here's why they have a separate
-identity:
+much like the ones defined in :mod:`webob.exc`, (e.g.,
+:class:`~pyramid.httpexceptions.HTTPNotFound` or
+:class:`~pyramid.httpexceptions.HTTPForbidden`). They have the same names and
+largely the same behavior, and all have a very similar implementation, but not
+the same identity. Here's why they have a separate identity:
- Making them separate allows the HTTP exception classes to subclass
:class:`pyramid.response.Response`. This speeds up response generation
- slightly due to the way the Pyramid router works. The same speedup could
- be gained by monkeypatching ``webob.response.Response`` but it's usually
+ slightly due to the way the Pyramid router works. The same speedup could be
+ gained by monkeypatching :class:`webob.response.Response`, but it's usually
the case that monkeypatching turns out to be evil and wrong.
- Making them separate allows them to provide alternate ``__call__`` logic
@@ -933,7 +928,7 @@ identity:
value of ``RequestClass`` (:class:`pyramid.request.Request`).
- Making them separate allows us freedom from having to think about backwards
- compatibility code present in ``webob.exc`` having to do with Python 2.4,
+ compatibility code present in :mod:`webob.exc` having to do with Python 2.4,
which we no longer support in Pyramid 1.1+.
- We change the behavior of two classes
@@ -944,9 +939,9 @@ identity:
- Making them separate allows us to influence the docstrings of the exception
classes to provide Pyramid-specific documentation.
-- Making them separate allows us to silence a stupid deprecation warning
- under Python 2.6 when the response objects are used as exceptions (related
- to ``self.message``).
+- Making them separate allows us to silence a stupid deprecation warning under
+ Python 2.6 when the response objects are used as exceptions (related to
+ ``self.message``).
.. _simpler_traversal_model:
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 9c0ea8598..60e861597 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -273,7 +273,7 @@ Glossary
(Allow, 'bob', 'read'), (Deny, 'fred', 'write')]``. If an ACL is
attached to a resource instance, and that resource is findable via the
context resource, it will be consulted any active security policy to
- determine wither a particular request can be fulfilled given the
+ determine whether a particular request can be fulfilled given the
:term:`authentication` information in the request.
authentication
@@ -1089,3 +1089,7 @@ Glossary
data in a Redis database. See
https://pypi.python.org/pypi/pyramid_redis_sessions for more information.
+ cache busting
+ A technique used when serving a cacheable static asset in order to force
+ a client to query the new version of the asset. See :ref:`cache_busting`
+ for more information.
diff --git a/docs/index.rst b/docs/index.rst
index 0ee3557bf..8c8a0a18d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,10 +4,9 @@
The Pyramid Web Framework
=========================
-:app:`Pyramid` is a small, fast, down-to-earth Python web framework. It
-is developed as part of the `Pylons Project
-<http://docs.pylonsproject.org/>`_. It is licensed under a `BSD-like license
-<http://repoze.org/license.html>`_.
+:app:`Pyramid` is a small, fast, down-to-earth Python web framework. It is
+developed as part of the `Pylons Project <http://docs.pylonsproject.org/>`_.
+It is licensed under a `BSD-like license <http://repoze.org/license.html>`_.
Here is one of the simplest :app:`Pyramid` applications you can make:
@@ -15,30 +14,17 @@ Here is one of the simplest :app:`Pyramid` applications you can make:
After you install :app:`Pyramid` and run this application, when you visit
`<http://localhost:8080/hello/world>`_ in a browser, you will see the text
-``Hello, world!``
+``Hello, world!`` See :ref:`firstapp_chapter` for a full explanation of how
+this application works.
-See :ref:`firstapp_chapter` for a full explanation of how this application
-works. Read the :ref:`html_narrative_documentation` to understand how
-:app:`Pyramid` is designed to scale from simple applications like this to
-very large web applications. To just dive in headfirst, read the
-:doc:`quick_tour`.
-
-Front Matter
-============
-
-.. toctree::
- :maxdepth: 1
-
- copyright.rst
- conventions.rst
.. _html_getting_started:
Getting Started
===============
-If you are new to Pyramid, we have a few resources that can help you get
-up to speed right away.
+If you are new to Pyramid, we have a few resources that can help you get up to
+speed right away.
.. toctree::
:hidden:
@@ -46,26 +32,69 @@ up to speed right away.
quick_tour
quick_tutorial/index
-* :doc:`quick_tour` goes through the major features in Pyramid, covering
- a little about a lot.
+* :doc:`quick_tour` gives an overview of the major features in Pyramid,
+ covering a little about a lot.
+
+* :doc:`quick_tutorial/index` is similar to the Quick Tour, but in a tutorial
+ format, with somewhat deeper treatment of each topic and with working code.
+
+* Like learning by example? Visit the official :ref:`html_tutorials` as well as
+ the community-contributed :ref:`Pyramid tutorials
+ <tutorials:pyramid-tutorials>`, which include a :ref:`Todo List Application
+ in One File <tutorials:single-file-tutorial>`.
+
+* For help getting Pyramid set up, try :ref:`installing_chapter`.
+
+* Need help? See :ref:`Support and Development <support-and-development>`.
+
+
+.. _html_tutorials:
+
+Tutorials
+=========
+
+Official tutorials explaining how to use :app:`Pyramid` to build various types
+of applications, and how to deploy :app:`Pyramid` applications to various
+platforms.
+
+.. toctree::
+ :maxdepth: 1
+
+ tutorials/wiki2/index.rst
+ tutorials/wiki/index.rst
+ tutorials/modwsgi/index.rst
+
+
+.. _support-and-development:
+
+Support and Development
+=======================
+
+The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
+source of :app:`Pyramid` support and development information.
-* :doc:`quick_tutorial/index` does the same, but in a tutorial format:
- deeper treatment of each topic and with working code.
+To report bugs, use the `issue tracker
+<https://github.com/Pylons/pyramid/issues>`_.
-* To see a minimal Pyramid web application, check out
- :ref:`firstapp_chapter`.
+If you've got questions that aren't answered by this documentation, contact the
+`Pylons-discuss maillist <http://groups.google.com/group/pylons-discuss>`_ or
+join the `#pyramid IRC channel <irc://irc.freenode.net/#pyramid>`_.
-* For help getting Pyramid set up, try
- :ref:`installing_chapter`.
+Browse and check out tagged and trunk versions of :app:`Pyramid` via the
+`Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_. To check out
+the trunk via ``git``, use either command:
-* Like learning by example? Visit the official
- :doc:`wiki tutorial <../tutorials/wiki2/index>` as well as the
- community-contributed
- :ref:`Pyramid tutorials <tutorials:pyramid-tutorials>`, which include
- a :ref:`single file tasks tutorial <tutorials:single-file-tutorial>`.
+.. code-block:: text
-* Need help? See :ref:`Support and
- Development <support-and-development>`.
+ # If you have SSH keys configured on GitHub:
+ git clone git@github.com:Pylons/pyramid.git
+
+ # Otherwise, HTTPS will work, using your GitHub login:
+ git clone https://github.com/Pylons/pyramid.git
+
+To find out how to become a contributor to :app:`Pyramid`, please see the
+`contributor's section of the documentation
+<http://docs.pylonsproject.org/en/latest/#contributing>`_.
.. _html_narrative_documentation:
@@ -73,8 +102,7 @@ up to speed right away.
Narrative Documentation
=======================
-Narrative documentation in chapter form explaining how to use
-:app:`Pyramid`.
+Narrative documentation in chapter form explaining how to use :app:`Pyramid`.
.. toctree::
:maxdepth: 2
@@ -119,33 +147,33 @@ Narrative documentation in chapter form explaining how to use
narr/threadlocals
narr/zca
-.. _html_tutorials:
-Tutorials
-=========
+API Documentation
+=================
-Tutorials explaining how to use :app:`Pyramid` to build various types of
-applications, and how to deploy :app:`Pyramid` applications to various
-platforms.
+Comprehensive reference material for every public API exposed by
+:app:`Pyramid`:
.. toctree::
- :maxdepth: 2
+ :maxdepth: 1
+ :glob:
- tutorials/wiki2/index.rst
- tutorials/wiki/index.rst
- tutorials/modwsgi/index.rst
+ api/index
+ api/*
-API Documentation
-=================
-Comprehensive reference material for every public API exposed by :app:`Pyramid`:
+``p*`` Scripts Documentation
+============================
+
+``p*`` scripts included with :app:`Pyramid`:.
.. toctree::
:maxdepth: 1
:glob:
- api/index
- api/*
+ pscripts/index
+ pscripts/*
+
Change History
==============
@@ -162,6 +190,7 @@ Change History
whatsnew-1.0
changes
+
Design Documents
================
@@ -170,33 +199,24 @@ Design Documents
designdefense
-.. _support-and-development:
-Support and Development
-=======================
+Copyright, Trademarks, and Attributions
+=======================================
-The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
-source of :app:`Pyramid` support and development information.
+.. toctree::
+ :maxdepth: 1
-To report bugs, use the `issue tracker
-<https://github.com/Pylons/pyramid/issues>`_.
+ copyright
-If you've got questions that aren't answered by this documentation,
-contact the `Pylons-discuss maillist
-<http://groups.google.com/group/pylons-discuss>`_ or join the `#pyramid
-IRC channel <irc://irc.freenode.net/#pyramid>`_.
-Browse and check out tagged and trunk versions of :app:`Pyramid` via
-the `Pyramid GitHub repository <https://github.com/Pylons/pyramid/>`_.
-To check out the trunk via ``git``, use this command:
+Typographical Conventions
+=========================
-.. code-block:: text
+.. toctree::
+ :maxdepth: 1
- git clone git@github.com:Pylons/pyramid.git
+ conventions
-To find out how to become a contributor to :app:`Pyramid`, please see the
-`contributor's section of the documentation
-<http://docs.pylonsproject.org/en/latest/#contributing>`_.
Index and Glossary
==================
diff --git a/docs/narr/MyProject/development.ini b/docs/narr/MyProject/development.ini
index a9a26e56b..749e574eb 100644
--- a/docs/narr/MyProject/development.ini
+++ b/docs/narr/MyProject/development.ini
@@ -11,7 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
+pyramid.includes =
pyramid_debugtoolbar
# By default, the toolbar only appears for clients from IP addresses
@@ -24,7 +24,7 @@ pyramid.includes =
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
+host = 127.0.0.1
port = 6543
###
@@ -57,4 +57,4 @@ level = NOTSET
formatter = generic
[formatter_generic]
-format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
diff --git a/docs/narr/MyProject/myproject/templates/mytemplate.pt b/docs/narr/MyProject/myproject/templates/mytemplate.pt
index e6b00a145..65d7f0609 100644
--- a/docs/narr/MyProject/myproject/templates/mytemplate.pt
+++ b/docs/narr/MyProject/myproject/templates/mytemplate.pt
@@ -8,12 +8,12 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="${request.static_url('myproject:static/pyramid-16x16.png')}">
- <title>Starter Template for The Pyramid Web Framework</title>
+ <title>Starter Scaffold for The Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
- <!-- Custom styles for this template -->
+ <!-- Custom styles for this scaffold -->
<link href="${request.static_url('myproject:static/theme.css')}" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
@@ -33,19 +33,20 @@
</div>
<div class="col-md-10">
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">starter template</span></h1>
- <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter scaffold</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.6b2</span>.</p>
</div>
</div>
</div>
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Currently v1.5</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org">Docs</a></li>
+ <li class="current-version">Generated by v1.6b2</li>
+ <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.6-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>
+ </ul>
</div>
</div>
<div class="row">
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index 8c60407e5..37df08a2a 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -16,31 +16,6 @@ class ViewTests(unittest.TestCase):
info = my_view(request)
self.assertEqual(info['project'], 'MyProject')
-class ViewIntegrationTests(unittest.TestCase):
- def setUp(self):
- """ This sets up the application registry with the
- registrations your application declares in its ``includeme``
- function.
- """
- self.config = testing.setUp()
- self.config.include('myproject')
-
- def tearDown(self):
- """ Clear out the application registry """
- testing.tearDown()
-
- def test_my_view(self):
- from myproject.views import my_view
- request = testing.DummyRequest()
- result = my_view(request)
- self.assertEqual(result.status, '200 OK')
- body = result.app_iter[0]
- self.assertTrue('Welcome to' in body)
- self.assertEqual(len(result.headerlist), 2)
- self.assertEqual(result.headerlist[0],
- ('Content-Type', 'text/html; charset=UTF-8'))
- self.assertEqual(result.headerlist[1], ('Content-Length',
- str(len(body))))
class FunctionalTests(unittest.TestCase):
def setUp(self):
diff --git a/docs/narr/MyProject/production.ini b/docs/narr/MyProject/production.ini
index 9eae9e03f..3ccbe6619 100644
--- a/docs/narr/MyProject/production.ini
+++ b/docs/narr/MyProject/production.ini
@@ -51,4 +51,4 @@ level = NOTSET
formatter = generic
[formatter_generic]
-format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
diff --git a/docs/narr/MyProject/setup.py b/docs/narr/MyProject/setup.py
index 9f34540a7..8c019af51 100644
--- a/docs/narr/MyProject/setup.py
+++ b/docs/narr/MyProject/setup.py
@@ -1,42 +1,30 @@
-"""Setup for the MyProject package.
-
-"""
import os
-from setuptools import setup, find_packages
-
-
-HERE = os.path.abspath(os.path.dirname(__file__))
-
-with open(os.path.join(HERE, 'README.txt')) as fp:
- README = fp.read()
-
-
-with open(os.path.join(HERE, 'CHANGES.txt')) as fp:
- CHANGES = fp.read()
+from setuptools import setup, find_packages
+here = os.path.abspath(os.path.dirname(__file__))
+with open(os.path.join(here, 'README.txt')) as f:
+ README = f.read()
+with open(os.path.join(here, 'CHANGES.txt')) as f:
+ CHANGES = f.read()
-REQUIRES = [
+requires = [
'pyramid',
'pyramid_chameleon',
'pyramid_debugtoolbar',
'waitress',
]
-TESTS_REQUIRE = [
- 'webtest'
- ]
-
setup(name='MyProject',
version='0.0',
description='MyProject',
long_description=README + '\n\n' + CHANGES,
classifiers=[
- 'Programming Language :: Python',
- 'Framework :: Pyramid',
- 'Topic :: Internet :: WWW/HTTP',
- 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
- ],
+ "Programming Language :: Python",
+ "Framework :: Pyramid",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
+ ],
author='',
author_email='',
url='',
@@ -44,10 +32,11 @@ setup(name='MyProject',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
- install_requires=REQUIRES,
- tests_require=TESTS_REQUIRE,
- test_suite='myproject',
+ install_requires=requires,
+ tests_require=requires,
+ test_suite="myproject",
entry_points="""\
[paste.app_factory]
main = myproject:main
- """)
+ """,
+ )
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 9ceaaa495..ba9bd1352 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -6,12 +6,11 @@
Advanced Configuration
======================
-To support application extensibility, the :app:`Pyramid`
-:term:`Configurator`, by default, detects configuration conflicts and allows
-you to include configuration imperatively from other packages or modules. It
-also, by default, performs configuration in two separate phases. This allows
-you to ignore relative configuration statement ordering in some
-circumstances.
+To support application extensibility, the :app:`Pyramid` :term:`Configurator`
+by default detects configuration conflicts and allows you to include
+configuration imperatively from other packages or modules. It also by default
+performs configuration in two separate phases. This allows you to ignore
+relative configuration statement ordering in some circumstances.
.. index::
pair: configuration; conflict detection
@@ -70,11 +69,11 @@ try to add another view to the configuration with the same set of
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-The application now has two conflicting view configuration statements. When
-we try to start it again, it won't start. Instead, we'll receive a traceback
-that ends something like this:
+The application now has two conflicting view configuration statements. When we
+try to start it again, it won't start. Instead we'll receive a traceback that
+ends something like this:
-.. code-block:: guess
+.. code-block:: text
:linenos:
Traceback (most recent call last):
@@ -94,19 +93,19 @@ that ends something like this:
This traceback is trying to tell us:
-- We've got conflicting information for a set of view configuration
- statements (The ``For:`` line).
+- We've got conflicting information for a set of view configuration statements
+ (The ``For:`` line).
- There are two statements which conflict, shown beneath the ``For:`` line:
``config.add_view(hello_world. 'hello')`` on line 14 of ``app.py``, and
``config.add_view(goodbye_world, 'hello')`` on line 17 of ``app.py``.
-These two configuration statements are in conflict because we've tried to
-tell the system that the set of :term:`predicate` values for both view
+These two configuration statements are in conflict because we've tried to tell
+the system that the set of :term:`predicate` values for both view
configurations are exactly the same. Both the ``hello_world`` and
``goodbye_world`` views are configured to respond under the same set of
-circumstances. This circumstance: the :term:`view name` (represented by the
-``name=`` predicate) is ``hello``.
+circumstances. This circumstance, the :term:`view name` represented by the
+``name=`` predicate, is ``hello``.
This presents an ambiguity that :app:`Pyramid` cannot resolve. Rather than
allowing the circumstance to go unreported, by default Pyramid raises a
@@ -138,8 +137,7 @@ made by your application. Use the detail provided in the
modify your configuration code accordingly.
If you're getting a conflict while trying to extend an existing application,
-and that application has a function which performs configuration like this
-one:
+and that application has a function which performs configuration like this one:
.. code-block:: python
:linenos:
@@ -147,8 +145,8 @@ one:
def add_routes(config):
config.add_route(...)
-Don't call this function directly with ``config`` as an argument. Instead,
-use :meth:`pyramid.config.Configurator.include`:
+Don't call this function directly with ``config`` as an argument. Instead, use
+:meth:`pyramid.config.Configurator.include`:
.. code-block:: python
:linenos:
@@ -156,9 +154,9 @@ use :meth:`pyramid.config.Configurator.include`:
config.include(add_routes)
Using :meth:`~pyramid.config.Configurator.include` instead of calling the
-function directly provides a modicum of automated conflict resolution, with
-the configuration statements you define in the calling code overriding those
-of the included function.
+function directly provides a modicum of automated conflict resolution, with the
+configuration statements you define in the calling code overriding those of the
+included function.
.. seealso::
@@ -169,10 +167,10 @@ Using ``config.commit()``
+++++++++++++++++++++++++
You can manually commit a configuration by using the
-:meth:`~pyramid.config.Configurator.commit` method between configuration
-calls. For example, we prevent conflicts from occurring in the application
-we examined previously as the result of adding a ``commit``. Here's the
-application that generates conflicts:
+:meth:`~pyramid.config.Configurator.commit` method between configuration calls.
+For example, we prevent conflicts from occurring in the application we examined
+previously as the result of adding a ``commit``. Here's the application that
+generates conflicts:
.. code-block:: python
:linenos:
@@ -199,11 +197,12 @@ application that generates conflicts:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-We can prevent the two ``add_view`` calls from conflicting by issuing a call
-to :meth:`~pyramid.config.Configurator.commit` between them:
+We can prevent the two ``add_view`` calls from conflicting by issuing a call to
+:meth:`~pyramid.config.Configurator.commit` between them:
.. code-block:: python
:linenos:
+ :emphasize-lines: 16
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -230,21 +229,20 @@ to :meth:`~pyramid.config.Configurator.commit` between them:
server.serve_forever()
In the above example we've issued a call to
-:meth:`~pyramid.config.Configurator.commit` between the two ``add_view``
-calls. :meth:`~pyramid.config.Configurator.commit` will execute any pending
+:meth:`~pyramid.config.Configurator.commit` between the two ``add_view`` calls.
+:meth:`~pyramid.config.Configurator.commit` will execute any pending
configuration statements.
Calling :meth:`~pyramid.config.Configurator.commit` is safe at any time. It
-executes all pending configuration actions and leaves the configuration
-action list "clean".
+executes all pending configuration actions and leaves the configuration action
+list "clean".
-Note that :meth:`~pyramid.config.Configurator.commit` has no effect when
-you're using an *autocommitting* configurator (see
-:ref:`autocommitting_configurator`).
+Note that :meth:`~pyramid.config.Configurator.commit` has no effect when you're
+using an *autocommitting* configurator (see :ref:`autocommitting_configurator`).
.. _autocommitting_configurator:
-Using An Autocommitting Configurator
+Using an Autocommitting Configurator
++++++++++++++++++++++++++++++++++++
You can also use a heavy hammer to circumvent conflict detection by using a
@@ -278,17 +276,17 @@ Automatic Conflict Resolution
If your code uses the :meth:`~pyramid.config.Configurator.include` method to
include external configuration, some conflicts are automatically resolved.
Configuration statements that are made as the result of an "include" will be
-overridden by configuration statements that happen within the caller of
-the "include" method.
+overridden by configuration statements that happen within the caller of the
+"include" method.
-Automatic conflict resolution supports this goal: if a user wants to reuse a
+Automatic conflict resolution supports this goal. If a user wants to reuse a
Pyramid application, and they want to customize the configuration of this
application without hacking its code "from outside", they can "include" a
configuration function from the package and override only some of its
configuration statements within the code that does the include. No conflicts
will be generated by configuration statements within the code that does the
-including, even if configuration statements in the included code would
-conflict if it was moved "up" to the calling code.
+including, even if configuration statements in the included code would conflict
+if it was moved "up" to the calling code.
Methods Which Provide Conflict Detection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -312,9 +310,9 @@ These are the methods of the configurator which provide conflict detection:
:meth:`~pyramid.config.Configurator.add_resource_url_adapter`,
and :meth:`~pyramid.config.Configurator.add_response_adapter`.
-:meth:`~pyramid.config.Configurator.add_static_view` also indirectly
-provides conflict detection, because it's implemented in terms of the
-conflict-aware ``add_route`` and ``add_view`` methods.
+:meth:`~pyramid.config.Configurator.add_static_view` also indirectly provides
+conflict detection, because it's implemented in terms of the conflict-aware
+``add_route`` and ``add_view`` methods.
.. index::
pair: configuration; including from external sources
@@ -324,10 +322,10 @@ conflict-aware ``add_route`` and ``add_view`` methods.
Including Configuration from External Sources
---------------------------------------------
-Some application programmers will factor their configuration code in such a
-way that it is easy to reuse and override configuration statements. For
-example, such a developer might factor out a function used to add routes to
-his application:
+Some application programmers will factor their configuration code in such a way
+that it is easy to reuse and override configuration statements. For example,
+such a developer might factor out a function used to add routes to their
+application:
.. code-block:: python
:linenos:
@@ -335,8 +333,8 @@ his application:
def add_routes(config):
config.add_route(...)
-Rather than calling this function directly with ``config`` as an argument.
-Instead, use :meth:`pyramid.config.Configurator.include`:
+Rather than calling this function directly with ``config`` as an argument,
+instead use :meth:`pyramid.config.Configurator.include`:
.. code-block:: python
:linenos:
@@ -363,21 +361,21 @@ the special name ``includeme``, which should perform configuration (like the
:meth:`~pyramid.config.Configurator.include` can also accept a :term:`dotted
Python name` to a function or a module.
-.. note: See :ref:`the_include_tag` for a declarative alternative to
- the :meth:`~pyramid.config.Configurator.include` method.
+.. note:: See :ref:`the_include_tag` for a declarative alternative to the
+ :meth:`~pyramid.config.Configurator.include` method.
.. _twophase_config:
Two-Phase Configuration
-----------------------
-When a non-autocommitting :term:`Configurator` is used to do configuration
-(the default), configuration execution happens in two phases. In the first
-phase, "eager" configuration actions (actions that must happen before all
-others, such as registering a renderer) are executed, and *discriminators*
-are computed for each of the actions that depend on the result of the eager
-actions. In the second phase, the discriminators of all actions are compared
-to do conflict detection.
+When a non-autocommitting :term:`Configurator` is used to do configuration (the
+default), configuration execution happens in two phases. In the first phase,
+"eager" configuration actions (actions that must happen before all others, such
+as registering a renderer) are executed, and *discriminators* are computed for
+each of the actions that depend on the result of the eager actions. In the
+second phase, the discriminators of all actions are compared to do conflict
+detection.
Due to this, for configuration methods that have no internal ordering
constraints, execution order of configuration method calls is not important.
@@ -401,15 +399,14 @@ Has the same result as:
config.add_view('some.view', renderer='path_to_custom/renderer.rn')
Even though the view statement depends on the registration of a custom
-renderer, due to two-phase configuration, the order in which the
-configuration statements are issued is not important. ``add_view`` will be
-able to find the ``.rn`` renderer even if ``add_renderer`` is called after
-``add_view``.
+renderer, due to two-phase configuration, the order in which the configuration
+statements are issued is not important. ``add_view`` will be able to find the
+``.rn`` renderer even if ``add_renderer`` is called after ``add_view``.
The same is untrue when you use an *autocommitting* configurator (see
:ref:`autocommitting_configurator`). When an autocommitting configurator is
-used, two-phase configuration is disabled, and configuration statements must
-be ordered in dependency order.
+used, two-phase configuration is disabled, and configuration statements must be
+ordered in dependency order.
Some configuration methods, such as
:meth:`~pyramid.config.Configurator.add_route` have internal ordering
@@ -420,7 +417,7 @@ added in configuration execution order.
More Information
----------------
-For more information, see the article, `"A Whirlwind Tour of Advanced
+For more information, see the article `"A Whirlwind Tour of Advanced
Configuration Tactics"
-<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_,
+<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_
in the Pyramid Cookbook.
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index 020794062..58f547fc9 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -356,247 +356,231 @@ may change, and then you'll want the client to load a new copy of the asset.
Under normal circumstances you'd just need to wait for the client's cached copy
to expire before they get the new version of the static resource.
-A commonly used workaround to this problem is a technique known as "cache
-busting". Cache busting schemes generally involve generating a URL for a
-static asset that changes when the static asset changes. This way headers can
-be sent along with the static asset instructing the client to cache the asset
-for a very long time. When a static asset is changed, the URL used to refer to
-it in a web page also changes, so the client sees it as a new resource and
-requests the asset, regardless of any caching policy set for the resource's old
-URL.
+A commonly used workaround to this problem is a technique known as
+:term:`cache busting`. Cache busting schemes generally involve generating a
+URL for a static asset that changes when the static asset changes. This way
+headers can be sent along with the static asset instructing the client to cache
+the asset for a very long time. When a static asset is changed, the URL used
+to refer to it in a web page also changes, so the client sees it as a new
+resource and requests the asset, regardless of any caching policy set for the
+resource's old URL.
:app:`Pyramid` can be configured to produce cache busting URLs for static
-assets by passing the optional argument, ``cachebust`` to
-:meth:`~pyramid.config.Configurator.add_static_view`:
+assets using :meth:`~pyramid.config.Configurator.add_cache_buster`:
.. code-block:: python
:linenos:
+ import time
+ from pyramid.static import QueryStringConstantCacheBuster
+
# config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static',
- cachebust=True)
+ config.add_static_view(name='static', path='mypackage:folder/static/')
+ config.add_cache_buster(
+ 'mypackage:folder/static/',
+ QueryStringConstantCacheBuster(str(int(time.time()))))
-Setting the ``cachebust`` argument instructs :app:`Pyramid` to use a cache
-busting scheme which adds the md5 checksum for a static asset as a path segment
-in the asset's URL:
+Adding the cachebuster instructs :app:`Pyramid` to add the current time for
+a static asset to the query string in the asset's URL:
.. code-block:: python
:linenos:
js_url = request.static_url('mypackage:folder/static/js/myapp.js')
- # Returns: 'http://www.example.com/static/c9658b3c0a314a1ca21e5988e662a09e/js/myapp.js'
+ # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121'
-When the asset changes, so will its md5 checksum, and therefore so will its
-URL. Supplying the ``cachebust`` argument also causes the static view to set
-headers instructing clients to cache the asset for ten years, unless the
-``cache_max_age`` argument is also passed, in which case that value is used.
+When the web server restarts, the time constant will change and therefore so
+will its URL.
.. note::
- md5 checksums are cached in RAM, so if you change a static resource without
- restarting your application, you may still generate URLs with a stale md5
- checksum.
+ Cache busting is an inherently complex topic as it integrates the asset
+ pipeline and the web application. It is expected and desired that
+ application authors will write their own cache buster implementations
+ conforming to the properties of their own asset pipelines. See
+ :ref:`custom_cache_busters` for information on writing your own.
Disabling the Cache Buster
~~~~~~~~~~~~~~~~~~~~~~~~~~
It can be useful in some situations (e.g., development) to globally disable all
configured cache busters without changing calls to
-:meth:`~pyramid.config.Configurator.add_static_view`. To do this set the
+:meth:`~pyramid.config.Configurator.add_cache_buster`. To do this set the
``PYRAMID_PREVENT_CACHEBUST`` environment variable or the
``pyramid.prevent_cachebust`` configuration value to a true value.
+.. _custom_cache_busters:
+
Customizing the Cache Buster
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Revisiting from the previous section:
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static',
- cachebust=True)
-
-Setting ``cachebust`` to ``True`` instructs :app:`Pyramid` to use a default
-cache busting implementation that should work for many situations. The
-``cachebust`` may be set to any object that implements the interface
-:class:`~pyramid.interfaces.ICacheBuster`. The above configuration is exactly
-equivalent to:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.static import PathSegmentMd5CacheBuster
+Calls to :meth:`~pyramid.config.Configurator.add_cache_buster` may use
+any object that implements the interface
+:class:`~pyramid.interfaces.ICacheBuster`.
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static',
- cachebust=PathSegmentMd5CacheBuster())
-
-:app:`Pyramid` includes a handful of ready to use cache buster implementations:
-:class:`~pyramid.static.PathSegmentMd5CacheBuster`, which inserts an md5
-checksum token in the path portion of the asset's URL,
-:class:`~pyramid.static.QueryStringMd5CacheBuster`, which adds an md5 checksum
-token to the query string of the asset's URL, and
+:app:`Pyramid` ships with a very simplistic
:class:`~pyramid.static.QueryStringConstantCacheBuster`, which adds an
-arbitrary token you provide to the query string of the asset's URL.
+arbitrary token you provide to the query string of the asset's URL. This
+is almost never what you want in production as it does not allow fine-grained
+busting of individual assets.
In order to implement your own cache buster, you can write your own class from
scratch which implements the :class:`~pyramid.interfaces.ICacheBuster`
interface. Alternatively you may choose to subclass one of the existing
implementations. One of the most likely scenarios is you'd want to change the
-way the asset token is generated. To do this just subclass either
-:class:`~pyramid.static.PathSegmentCacheBuster` or
+way the asset token is generated. To do this just subclass
:class:`~pyramid.static.QueryStringCacheBuster` and define a
-``tokenize(pathspec)`` method. Here is an example which just uses Git to get
-the hash of the currently checked out code:
+``tokenize(pathspec)`` method. Here is an example which uses Git to get
+the hash of the current commit:
.. code-block:: python
:linenos:
import os
import subprocess
- from pyramid.static import PathSegmentCacheBuster
+ from pyramid.static import QueryStringCacheBuster
- class GitCacheBuster(PathSegmentCacheBuster):
+ class GitCacheBuster(QueryStringCacheBuster):
"""
Assuming your code is installed as a Git checkout, as opposed to an egg
from an egg repository like PYPI, you can use this cachebuster to get
the current commit's SHA1 to use as the cache bust token.
"""
- def __init__(self):
- here = os.path.dirname(os.path.abspath(__file__))
+ def __init__(self, param='x', repo_path=None):
+ super(GitCacheBuster, self).__init__(param=param)
+ if repo_path is None:
+ repo_path = os.path.dirname(os.path.abspath(__file__))
self.sha1 = subprocess.check_output(
['git', 'rev-parse', 'HEAD'],
- cwd=here).strip()
+ cwd=repo_path).strip()
def tokenize(self, pathspec):
return self.sha1
-Choosing a Cache Buster
-~~~~~~~~~~~~~~~~~~~~~~~
-
-The default cache buster implementation,
-:class:`~pyramid.static.PathSegmentMd5CacheBuster`, works very well assuming
-that you're using :app:`Pyramid` to serve your static assets. The md5 checksum
-is fine grained enough that browsers should only request new versions of
-specific assets that have changed. Many caching HTTP proxies will fail to
-cache a resource if the URL contains a query string. In general, therefore,
-you should prefer a cache busting strategy which modifies the path segment to a
-strategy which adds a query string.
-
-It is possible, however, that your static assets are being served by another
-web server or externally on a CDN. In these cases modifying the path segment
-for a static asset URL would cause the external service to fail to find the
-asset, causing your customer to get a 404. In these cases you would need to
-fall back to a cache buster which adds a query string. It is even possible
-that there isn't a copy of your static assets available to the :app:`Pyramid`
-application, so a cache busting implementation that generates md5 checksums
-would fail since it can't access the assets. In such a case,
-:class:`~pyramid.static.QueryStringConstantCacheBuster` is a reasonable
-fallback. The following code would set up a cachebuster that just uses the
-time at start up as a cachebust token:
+A simple cache buster that modifies the path segment can be constructed as
+well:
.. code-block:: python
:linenos:
- import time
- from pyramid.static import QueryStringConstantCacheBuster
-
- config.add_static_view(
- name='http://mycdn.example.com/',
- path='mypackage:static',
- cachebust=QueryStringConstantCacheBuster(str(time.time())))
-
-.. index::
- single: static assets view
-
-CSS and JavaScript source and cache busting
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Often one needs to refer to images and other static assets inside CSS and
-JavaScript files. If cache busting is active, the final static asset URL is not
-available until the static assets have been assembled. These URLs cannot be
-handwritten. Thus, when having static asset references in CSS and JavaScript,
-one needs to perform one of the following tasks.
+ import posixpath
-* Process the files by using a precompiler which rewrites URLs to their final
- cache busted form.
+ class PathConstantCacheBuster(object):
+ def __init__(self, token):
+ self.token = token
-* Templatize JS and CSS, and call ``request.static_url()`` inside their
- template code.
+ def __call__(self, request, subpath, kw):
+ base_subpath, ext = posixpath.splitext(subpath)
+ new_subpath = base_subpath + self.token + ext
+ return new_subpath, kw
-* Pass static URL references to CSS and JavaScript via other means.
+The caveat with this approach is that modifying the path segment
+changes the file name, and thus must match what is actually on the
+filesystem in order for :meth:`~pyramid.config.Configurator.add_static_view`
+to find the file. It's better to use the
+:class:`~pyramid.static.ManifestCacheBuster` for these situations, as
+described in the next section.
-Below are some simple approaches for CSS and JS programming which consider
-asset cache busting. These approaches do not require additional tools or
-packages.
+.. _path_segment_cache_busters:
-Relative cache busted URLs in CSS
-+++++++++++++++++++++++++++++++++
+Path Segments and Choosing a Cache Buster
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Consider a CSS file ``/static/theme/css/site.css`` which contains the following
-CSS code.
+Many caching HTTP proxies will fail to cache a resource if the URL contains
+a query string. Therefore, in general, you should prefer a cache busting
+strategy which modifies the path segment rather than methods which add a
+token to the query string.
-.. code-block:: css
+You will need to consider whether the :app:`Pyramid` application will be
+serving your static assets, whether you are using an external asset pipeline
+to handle rewriting urls internal to the css/javascript, and how fine-grained
+do you want the cache busting tokens to be.
- body {
- background: url(/static/theme/img/background.jpg);
- }
+In many cases you will want to host the static assets on another web server
+or externally on a CDN. In these cases your :app:`Pyramid` application may not
+even have access to a copy of the static assets. In order to cache bust these
+assets you will need some information about them.
-Any changes to ``background.jpg`` would not appear to the visitor because the
-URL path is not cache busted as it is. Instead we would have to construct an
-URL to the background image with the default ``PathSegmentCacheBuster`` cache
-busting mechanism::
+If you are using an external asset pipeline to generate your static files you
+should consider using the :class:`~pyramid.static.ManifestCacheBuster`.
+This cache buster can load a standard JSON formatted file generated by your
+pipeline and use it to cache bust the assets. This has many performance
+advantages as :app:`Pyramid` does not need to look at the files to generate
+any cache busting tokens, but still supports fine-grained per-file tokens.
- https://site/static/1eeb262c717/theme/img/background.jpg
+Assuming an example ``manifest.json`` like:
-Every time the image is updated, the URL would need to be changed. It is not
-practical to write this non-human readable URL into a CSS file.
+.. code-block:: json
-However, the CSS file itself is cache busted and is located under the path for
-static assets. This lets us use relative references in our CSS to cache bust
-the image.
+ {
+ "css/main.css": "css/main-678b7c80.css",
+ "images/background.png": "images/background-a8169106.png"
+ }
-.. code-block:: css
+The following code would set up a cachebuster:
- body {
- background: url(../img/background.jpg);
- }
+.. code-block:: python
+ :linenos:
-The browser would interpret this as having the CSS file hash in URL::
+ from pyramid.static import ManifestCacheBuster
- https://site/static/ab234b262c71/theme/css/../img/background.jpg
+ config.add_static_view(
+ name='http://mycdn.example.com/',
+ path='mypackage:static')
-The downside of this approach is that if the background image changes, one
-needs to bump the CSS file. The CSS file hash change signals the caches that
-the relative URL to the image in the CSS has been changed. When updating CSS
-and related image assets, updates usually happen hand in hand, so this does not
-add extra effort to theming workflow.
+ config.add_cache_buster(
+ 'mypackage:static/',
+ ManifestCacheBuster('myapp:static/manifest.json'))
-Passing cache busted URLs to JavaScript
-+++++++++++++++++++++++++++++++++++++++
+It's important to note that the cache buster only handles generating
+cache-busted URLs for static assets. It does **NOT** provide any solutions for
+serving those assets. For example, if you generated a URL for
+``css/main-678b7c80.css`` then that URL needs to be valid either by
+configuring ``add_static_view`` properly to point to the location of the files
+or some other mechanism such as the files existing on your CDN or rewriting
+the incoming URL to remove the cache bust tokens.
-For JavaScript, one can pass static asset URLs as function arguments or
-globals. The globals can be generated in page template code, having access to
-the ``request.static_url()`` function.
+.. index::
+ single: static assets view
-Below is a simple example of passing a cached busted image URL in the Jinja2
-template language. Put the following code into the ``<head>`` section of the
-relevant page.
+CSS and JavaScript source and cache busting
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. code-block:: html
+Often one needs to refer to images and other static assets inside CSS and
+JavaScript files. If cache busting is active, the final static asset URL is not
+available until the static assets have been assembled. These URLs cannot be
+handwritten. Below is an example of how to integrate the cache buster into
+the entire stack. Remember, it is just an example and should be modified to
+fit your specific tools.
- <script>
- window.assets.backgroundImage =
- "{{ '/theme/img/background.jpg'|static_url() }}";
- </script>
+* First, process the files by using a precompiler which rewrites URLs to their
+ final cache-busted form. Then, you can use the
+ :class:`~pyramid.static.ManifestCacheBuster` to synchronize your asset
+ pipeline with :app:`Pyramid`, allowing the pipeline to have full control
+ over the final URLs of your assets.
-Then in your main ``site.js`` file, put the following code.
+Now that you are able to generate static URLs within :app:`Pyramid`,
+you'll need to handle URLs that are out of our control. To do this you may
+use some of the following options to get started:
-.. code-block:: javascript
+* Configure your asset pipeline to rewrite URL references inline in
+ CSS and JavaScript. This is the best approach because then the files
+ may be hosted by :app:`Pyramid` or an external CDN without having to
+ change anything. They really are static.
- var image = new Image(window.assets.backgroundImage);
+* Templatize JS and CSS, and call ``request.static_url()`` inside their
+ template code. While this approach may work in certain scenarios, it is not
+ recommended because your static assets will not really be static and are now
+ dependent on :app:`Pyramid` to be served correctly. See
+ :ref:`advanced_static` for more information on this approach.
+
+If your CSS and JavaScript assets use URLs to reference other assets it is
+recommended that you implement an external asset pipeline that can rewrite the
+generated static files with new URLs containing cache busting tokens. The
+machinery inside :app:`Pyramid` will not help with this step as it has very
+little knowledge of the asset types your application may use. The integration
+into :app:`Pyramid` is simply for linking those assets into your HTML and
+other dynamic content.
.. _advanced_static:
@@ -835,3 +819,56 @@ when an override is used.
As of Pyramid 1.6, it is also possible to override an asset by supplying an
absolute path to a file or directory. This may be useful if the assets are
not distributed as part of a Python package.
+
+Cache Busting and Asset Overrides
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Overriding static assets that are being hosted using
+:meth:`pyramid.config.Configurator.add_static_view` can affect your cache
+busting strategy when using any cache busters that are asset-aware such as
+:class:`pyramid.static.ManifestCacheBuster`. What sets asset-aware cache
+busters apart is that they have logic tied to specific assets. For example,
+a manifest is only generated for a specific set of pre-defined assets. Now,
+imagine you have overridden an asset defined in this manifest with a new,
+unknown version. By default, the cache buster will be invoked for an asset
+it has never seen before and will likely end up returning a cache busting
+token for the original asset rather than the asset that will actually end up
+being served! In order to get around this issue, it's possible to attach a
+different :class:`pyramid.interfaces.ICacheBuster` implementation to the
+new assets. This would cause the original assets to be served by their
+manifest, and the new assets served by their own cache buster. To do this,
+:meth:`pyramid.config.Configurator.add_cache_buster` supports an ``explicit``
+option. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.static import ManifestCacheBuster
+
+ # define a static view for myapp:static assets
+ config.add_static_view('static', 'myapp:static')
+
+ # setup a cache buster for your app based on the myapp:static assets
+ my_cb = ManifestCacheBuster('myapp:static/manifest.json')
+ config.add_cache_buster('myapp:static', my_cb)
+
+ # override an asset
+ config.override_asset(
+ to_override='myapp:static/background.png',
+ override_with='theme:static/background.png')
+
+ # override the cache buster for theme:static assets
+ theme_cb = ManifestCacheBuster('theme:static/manifest.json')
+ config.add_cache_buster('theme:static', theme_cb, explicit=True)
+
+In the above example there is a default cache buster, ``my_cb``, for all
+assets served from the ``myapp:static`` folder. This would also affect
+``theme:static/background.png`` when generating URLs via
+``request.static_url('myapp:static/background.png')``.
+
+The ``theme_cb`` is defined explicitly for any assets loaded from the
+``theme:static`` folder. Explicit cache busters have priority and thus
+``theme_cb`` would be invoked for
+``request.static_url('myapp:static/background.png')``, but ``my_cb`` would
+be used for any other assets like
+``request.static_url('myapp:static/favicon.ico')``.
diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst
index 9db92b669..34b12e1e9 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -6,6 +6,7 @@ Command-Line Pyramid
Your :app:`Pyramid` application can be controlled and inspected using a variety
of command-line utilities. These utilities are documented in this chapter.
+
.. index::
pair: matching views; printing
single: pviews
@@ -15,6 +16,8 @@ of command-line utilities. These utilities are documented in this chapter.
Displaying Matching Views for a Given URL
-----------------------------------------
+.. seealso:: See also the output of :ref:`pviews --help <pviews_script>`.
+
For a big application with several views, it can be hard to keep the view
configuration details in your head, even if you defined all the views yourself.
You can use the ``pviews`` command in a terminal window to print a summary of
@@ -107,15 +110,15 @@ found* message.
.. index::
single: interactive shell
- single: IPython
single: pshell
- single: bpython
.. _interactive_shell:
The Interactive Shell
---------------------
+.. seealso:: See also the output of :ref:`pshell --help <pshell_script>`.
+
Once you've installed your program for development using ``setup.py develop``,
you can use an interactive Python shell to execute expressions in a Python
environment exactly like the one that will be used when your application runs
@@ -181,6 +184,7 @@ hash after the filename:
Press ``Ctrl-D`` to exit the interactive shell (or ``Ctrl-Z`` on Windows).
+
.. index::
pair: pshell; extending
@@ -263,38 +267,43 @@ request is configured to generate urls from the host
>>> request.route_url('home')
'https://www.example.com/'
-.. index::
- single: IPython
- single: bpython
.. _ipython_or_bpython:
-IPython or bpython
+Alternative Shells
~~~~~~~~~~~~~~~~~~
-If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ and/or `bpython
-<http://bpython-interpreter.org/>`_ in the interpreter you use to invoke the
-``pshell`` command, ``pshell`` will autodiscover and use the first one found,
-in this order: IPython, bpython, standard Python interpreter. However you could
-specifically invoke your choice with the ``-p choice`` or ``--python-shell
-choice`` option.
+The ``pshell`` command can be easily extended with alternate REPLs if the
+default python REPL is not satisfactory. Assuming you have a binding
+installed such as ``pyramid_ipython`` it will normally be auto-selected and
+used. You may also specifically invoke your choice with the ``-p choice`` or
+``--python-shell choice`` option.
.. code-block:: text
- $ $VENV/bin/pshell -p ipython | bpython | python development.ini#MyProject
+ $ $VENV/bin/pshell -p ipython development.ini#MyProject
+
+You may use the ``--list-shells`` option to see the available shells.
+
+.. code-block:: text
+
+ $ $VENV/bin/pshell --list-shells
+ Available shells:
+ bpython
+ ipython
+ python
-Alternative Shells
-~~~~~~~~~~~~~~~~~~
If you want to use a shell that isn't supported out of the box, you can
introduce a new shell by registering an entry point in your setup.py:
.. code-block:: python
setup(
- entry_points = """\
- [pyramid.pshell]
- myshell=my_app:ptpython_shell_factory
- """
+ entry_points={
+ 'pyramid.pshell_runner': [
+ 'myshell=my_app:ptpython_shell_factory',
+ ],
+ },
)
And then your shell factory should return a function that accepts two
@@ -302,19 +311,35 @@ arguments, ``env`` and ``help``, which would look like this:
.. code-block:: python
- def ptpython_shell_factory():
- from ptpython.repl import embed
- def PTPShell(banner, **kwargs):
- print(banner)
- return embed(**kwargs)
+ from ptpython.repl import embed
+
+ def ptpython_shell_runner(env, help):
+ print(help)
+ return embed(locals=env)
+
+.. versionchanged:: 1.6
+ User-defined shells may be registered using entry points. Prior to this
+ the only supported shells were ``ipython``, ``bpython`` and ``python``.
+
+ ``ipython`` and ``bpython`` have been moved into their respective
+ packages ``pyramid_ipython`` and ``pyramid_bpython``.
- def shell(env, help):
- PTPShell(banner=help, locals=env)
- return shell
+Setting a Default Shell
+~~~~~~~~~~~~~~~~~~~~~~~
+
+You may use the ``default_shell`` option in your ``[pshell]`` ini section to
+specify a list of preferred shells.
+
+.. code-block:: ini
+ :linenos:
+
+ [pshell]
+ default_shell = ptpython ipython bpython
.. versionadded:: 1.6
+
.. index::
pair: routes; printing
single: proutes
@@ -324,6 +349,8 @@ arguments, ``env`` and ``help``, which would look like this:
Displaying All Application Routes
---------------------------------
+.. seealso:: See also the output of :ref:`proutes --help <proutes_script>`.
+
You can use the ``proutes`` command in a terminal window to print a summary of
routes related to your application. Much like the ``pshell`` command (see
:ref:`interactive_shell`), the ``proutes`` command accepts one argument with
@@ -405,6 +432,8 @@ include. The current available formats are ``name``, ``pattern``, ``view``, and
Displaying "Tweens"
-------------------
+.. seealso:: See also the output of :ref:`ptweens --help <ptweens_script>`.
+
A :term:`tween` is a bit of code that sits between the main Pyramid application
request handler and the WSGI application which calls it. A user can get a
representation of both the implicit tween ordering (the ordering specified by
@@ -481,6 +510,7 @@ used:
See :ref:`registering_tweens` for more information about tweens.
+
.. index::
single: invoking a request
single: prequest
@@ -490,6 +520,8 @@ See :ref:`registering_tweens` for more information about tweens.
Invoking a Request
------------------
+.. seealso:: See also the output of :ref:`prequest --help <prequest_script>`.
+
You can use the ``prequest`` command-line utility to send a request to your
application and see the response body without starting a server.
@@ -539,6 +571,7 @@ of the ``prequest`` process is used as the ``POST`` body::
$ $VENV/bin/prequest -mPOST development.ini / < somefile
+
Using Custom Arguments to Python when Running ``p*`` Scripts
------------------------------------------------------------
@@ -550,11 +583,22 @@ Python interpreter at runtime. For example::
python -3 -m pyramid.scripts.pserve development.ini
+
+.. index::
+ single: pdistreport
+ single: distributions, showing installed
+ single: showing installed distributions
+
+.. _showing_distributions:
+
Showing All Installed Distributions and Their Versions
------------------------------------------------------
.. versionadded:: 1.5
+.. seealso:: See also the output of :ref:`pdistreport --help
+ <pdistreport_script>`.
+
You can use the ``pdistreport`` command to show the :app:`Pyramid` version in
use, the Python version in use, and all installed versions of Python
distributions in your Python environment::
@@ -574,6 +618,7 @@ pastebin when you are having problems and need someone with more familiarity
with Python packaging and distribution than you have to look at your
environment.
+
.. _writing_a_script:
Writing a Script
@@ -686,6 +731,7 @@ The above example specifies the ``another`` ``app``, ``pipeline``, or
object present in the ``env`` dictionary returned by
:func:`pyramid.paster.bootstrap` will be a :app:`Pyramid` :term:`router`.
+
Changing the Request
~~~~~~~~~~~~~~~~~~~~
@@ -726,6 +772,7 @@ Now you can readily use Pyramid's APIs for generating URLs:
env['request'].route_url('verify', code='1337')
# will return 'https://example.com/prefix/verify/1337'
+
Cleanup
~~~~~~~
@@ -741,6 +788,7 @@ callback:
env['closer']()
+
Setting Up Logging
~~~~~~~~~~~~~~~~~~
@@ -757,6 +805,7 @@ use the following command:
See :ref:`logging_chapter` for more information on logging within
:app:`Pyramid`.
+
.. index::
single: console script
diff --git a/docs/narr/extconfig.rst b/docs/narr/extconfig.rst
index a61eca7b7..fee8d0d3a 100644
--- a/docs/narr/extconfig.rst
+++ b/docs/narr/extconfig.rst
@@ -7,9 +7,9 @@ Extending Pyramid Configuration
===============================
Pyramid allows you to extend its Configurator with custom directives. Custom
-directives can use other directives, they can add a custom :term:`action`,
-they can participate in :term:`conflict resolution`, and they can provide
-some number of :term:`introspectable` objects.
+directives can use other directives, they can add a custom :term:`action`, they
+can participate in :term:`conflict resolution`, and they can provide some
+number of :term:`introspectable` objects.
.. index::
single: add_directive
@@ -20,18 +20,17 @@ some number of :term:`introspectable` objects.
Adding Methods to the Configurator via ``add_directive``
--------------------------------------------------------
-Framework extension writers can add arbitrary methods to a
-:term:`Configurator` by using the
-:meth:`pyramid.config.Configurator.add_directive` method of the configurator.
-Using :meth:`~pyramid.config.Configurator.add_directive` makes it possible to
-extend a Pyramid configurator in arbitrary ways, and allows it to perform
-application-specific tasks more succinctly.
+Framework extension writers can add arbitrary methods to a :term:`Configurator`
+by using the :meth:`pyramid.config.Configurator.add_directive` method of the
+configurator. Using :meth:`~pyramid.config.Configurator.add_directive` makes it
+possible to extend a Pyramid configurator in arbitrary ways, and allows it to
+perform application-specific tasks more succinctly.
The :meth:`~pyramid.config.Configurator.add_directive` method accepts two
-positional arguments: a method name and a callable object. The callable
-object is usually a function that takes the configurator instance as its
-first argument and accepts other arbitrary positional and keyword arguments.
-For example:
+positional arguments: a method name and a callable object. The callable object
+is usually a function that takes the configurator instance as its first
+argument and accepts other arbitrary positional and keyword arguments. For
+example:
.. code-block:: python
:linenos:
@@ -48,8 +47,8 @@ For example:
add_newrequest_subscriber)
Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can
-then call the added directive by its given name as if it were a built-in
-method of the Configurator:
+then call the added directive by its given name as if it were a built-in method
+of the Configurator:
.. code-block:: python
:linenos:
@@ -59,9 +58,9 @@ method of the Configurator:
config.add_newrequest_subscriber(mysubscriber)
-A call to :meth:`~pyramid.config.Configurator.add_directive` is often
-"hidden" within an ``includeme`` function within a "frameworky" package meant
-to be included as per :ref:`including_configuration` via
+A call to :meth:`~pyramid.config.Configurator.add_directive` is often "hidden"
+within an ``includeme`` function within a "frameworky" package meant to be
+included as per :ref:`including_configuration` via
:meth:`~pyramid.config.Configurator.include`. For example, if you put this
code in a package named ``pyramid_subscriberhelpers``:
@@ -72,8 +71,8 @@ code in a package named ``pyramid_subscriberhelpers``:
config.add_directive('add_newrequest_subscriber',
add_newrequest_subscriber)
-The user of the add-on package ``pyramid_subscriberhelpers`` would then be
-able to install it and subsequently do:
+The user of the add-on package ``pyramid_subscriberhelpers`` would then be able
+to install it and subsequently do:
.. code-block:: python
:linenos:
@@ -91,13 +90,12 @@ Using ``config.action`` in a Directive
If a custom directive can't do its work exclusively in terms of existing
configurator methods (such as
-:meth:`pyramid.config.Configurator.add_subscriber`, as above), the directive
-may need to make use of the :meth:`pyramid.config.Configurator.action`
-method. This method adds an entry to the list of "actions" that Pyramid will
-attempt to process when :meth:`pyramid.config.Configurator.commit` is called.
-An action is simply a dictionary that includes a :term:`discriminator`,
-possibly a callback function, and possibly other metadata used by Pyramid's
-action system.
+:meth:`pyramid.config.Configurator.add_subscriber` as above), the directive may
+need to make use of the :meth:`pyramid.config.Configurator.action` method. This
+method adds an entry to the list of "actions" that Pyramid will attempt to
+process when :meth:`pyramid.config.Configurator.commit` is called. An action is
+simply a dictionary that includes a :term:`discriminator`, possibly a callback
+function, and possibly other metadata used by Pyramid's action system.
Here's an example directive which uses the "action" method:
@@ -122,15 +120,15 @@ closure function named ``register`` is passed as the second argument named
When the :meth:`~pyramid.config.Configurator.action` method is called, it
appends an action to the list of pending configuration actions. All pending
-actions with the same discriminator value are potentially in conflict with
-one another (see :ref:`conflict_detection`). When the
+actions with the same discriminator value are potentially in conflict with one
+another (see :ref:`conflict_detection`). When the
:meth:`~pyramid.config.Configurator.commit` method of the Configurator is
called (either explicitly or as the result of calling
:meth:`~pyramid.config.Configurator.make_wsgi_app`), conflicting actions are
-potentially automatically resolved as per
-:ref:`automatic_conflict_resolution`. If a conflict cannot be automatically
-resolved, a :exc:`pyramid.exceptions.ConfigurationConflictError` is raised
-and application startup is prevented.
+potentially automatically resolved as per :ref:`automatic_conflict_resolution`.
+If a conflict cannot be automatically resolved, a
+:exc:`pyramid.exceptions.ConfigurationConflictError` is raised and application
+startup is prevented.
In our above example, therefore, if a consumer of our ``add_jammyjam``
directive did this:
@@ -146,14 +144,14 @@ generated by the two calls are in direct conflict. Automatic conflict
resolution cannot resolve the conflict (because no ``config.include`` is
involved), and the user provided no intermediate
:meth:`pyramid.config.Configurator.commit` call between the calls to
-``add_jammyjam`` to ensure that the successive calls did not conflict with
-each other.
+``add_jammyjam`` to ensure that the successive calls did not conflict with each
+other.
This demonstrates the purpose of the discriminator argument to the action
method: it's used to indicate a uniqueness constraint for an action. Two
actions with the same discriminator will conflict unless the conflict is
-automatically or manually resolved. A discriminator can be any hashable
-object, but it is generally a string or a tuple. *You use a discriminator to
+automatically or manually resolved. A discriminator can be any hashable object,
+but it is generally a string or a tuple. *You use a discriminator to
declaratively ensure that the user doesn't provide ambiguous configuration
statements.*
@@ -169,21 +167,20 @@ appended to the pending actions list. When the pending configuration actions
are processed during :meth:`~pyramid.config.Configurator.commit`, and no
conflicts occur, the *callable* provided as the second argument to the
:meth:`~pyramid.config.Configurator.action` method within ``add_jammyjam`` is
-called with no arguments. The callable in ``add_jammyjam`` is the
-``register`` closure function. It simply sets the value
-``config.registry.jammyjam`` to whatever the user passed in as the
-``jammyjam`` argument to the ``add_jammyjam`` function. Therefore, the
-result of the user's call to our directive will set the ``jammyjam``
-attribute of the registry to the string ``first``. *A callable is used by a
-directive to defer the result of a user's call to the directive until
-conflict detection has had a chance to do its job*.
+called with no arguments. The callable in ``add_jammyjam`` is the ``register``
+closure function. It simply sets the value ``config.registry.jammyjam`` to
+whatever the user passed in as the ``jammyjam`` argument to the
+``add_jammyjam`` function. Therefore, the result of the user's call to our
+directive will set the ``jammyjam`` attribute of the registry to the string
+``first``. *A callable is used by a directive to defer the result of a user's
+call to the directive until conflict detection has had a chance to do its job*.
Other arguments exist to the :meth:`~pyramid.config.Configurator.action`
-method, including ``args``, ``kw``, ``order``, and ``introspectables``.
+method, including ``args``, ``kw``, ``order``, and ``introspectables``.
-``args`` and ``kw`` exist as values, which, if passed, will be used as
-arguments to the ``callable`` function when it is called back. For example
-our directive might use them like so:
+``args`` and ``kw`` exist as values, which if passed will be used as arguments
+to the ``callable`` function when it is called back. For example, our
+directive might use them like so:
.. code-block:: python
:linenos:
@@ -198,31 +195,33 @@ our directive might use them like so:
In the above example, when this directive is used to generate an action, and
that action is committed, ``config.registry.jammyjam_args`` will be set to
``('one',)`` and ``config.registry.jammyjam_kw`` will be set to
-``{'two':'two'}``. ``args`` and ``kw`` are honestly not very useful when
-your ``callable`` is a closure function, because you already usually have
-access to every local in the directive without needing them to be passed
-back. They can be useful, however, if you don't use a closure as a callable.
+``{'two':'two'}``. ``args`` and ``kw`` are honestly not very useful when your
+``callable`` is a closure function, because you already usually have access to
+every local in the directive without needing them to be passed back. They can
+be useful, however, if you don't use a closure as a callable.
``order`` is a crude order control mechanism. ``order`` defaults to the
integer ``0``; it can be set to any other integer. All actions that share an
order will be called before other actions that share a higher order. This
makes it possible to write a directive with callable logic that relies on the
-execution of the callable of another directive being done first. For
-example, Pyramid's :meth:`pyramid.config.Configurator.add_view` directive
-registers an action with a higher order than the
+execution of the callable of another directive being done first. For example,
+Pyramid's :meth:`pyramid.config.Configurator.add_view` directive registers an
+action with a higher order than the
:meth:`pyramid.config.Configurator.add_route` method. Due to this, the
-``add_view`` method's callable can assume that, if a ``route_name`` was
-passed to it, that a route by this name was already registered by
-``add_route``, and if such a route has not already been registered, it's a
-configuration error (a view that names a nonexistent route via its
-``route_name`` parameter will never be called). As of Pyramid 1.6 it is
-possible for one action to invoke another. See :ref:`ordering_actions` for
-more information.
-
-``introspectables`` is a sequence of :term:`introspectable` objects. You can
-pass a sequence of introspectables to the
-:meth:`~pyramid.config.Configurator.action` method, which allows you to
-augment Pyramid's configuration introspection system.
+``add_view`` method's callable can assume that, if a ``route_name`` was passed
+to it, that a route by this name was already registered by ``add_route``, and
+if such a route has not already been registered, it's a configuration error (a
+view that names a nonexistent route via its ``route_name`` parameter will never
+be called).
+
+.. versionchanged:: 1.6
+ As of Pyramid 1.6 it is possible for one action to invoke another. See
+ :ref:`ordering_actions` for more information.
+
+Finally, ``introspectables`` is a sequence of :term:`introspectable` objects.
+You can pass a sequence of introspectables to the
+:meth:`~pyramid.config.Configurator.action` method, which allows you to augment
+Pyramid's configuration introspection system.
.. _ordering_actions:
@@ -233,18 +232,17 @@ In Pyramid every :term:`action` has an inherent ordering relative to other
actions. The logic within actions is deferred until a call to
:meth:`pyramid.config.Configurator.commit` (which is automatically invoked by
:meth:`pyramid.config.Configurator.make_wsgi_app`). This means you may call
-``config.add_view(route_name='foo')`` **before**
-``config.add_route('foo', '/foo')`` because nothing actually happens until
-commit-time. During a commit cycle conflicts are resolved, actions are ordered
-and executed.
+``config.add_view(route_name='foo')`` **before** ``config.add_route('foo',
+'/foo')`` because nothing actually happens until commit-time. During a commit
+cycle, conflicts are resolved, and actions are ordered and executed.
By default, almost every action in Pyramid has an ``order`` of
:const:`pyramid.config.PHASE3_CONFIG`. Every action within the same order-level
-will be executed in the order it was called.
-This means that if an action must be reliably executed before or after another
-action, the ``order`` must be defined explicitly to make this work. For
-example, views are dependent on routes being defined. Thus the action created
-by :meth:`pyramid.config.Configurator.add_route` has an ``order`` of
+will be executed in the order it was called. This means that if an action must
+be reliably executed before or after another action, the ``order`` must be
+defined explicitly to make this work. For example, views are dependent on
+routes being defined. Thus the action created by
+:meth:`pyramid.config.Configurator.add_route` has an ``order`` of
:const:`pyramid.config.PHASE2_CONFIG`.
Pre-defined Phases
@@ -252,8 +250,8 @@ Pre-defined Phases
:const:`pyramid.config.PHASE0_CONFIG`
-- This phase is reserved for developers who want to execute actions prior
- to Pyramid's core directives.
+- This phase is reserved for developers who want to execute actions prior to
+ Pyramid's core directives.
:const:`pyramid.config.PHASE1_CONFIG`
@@ -274,17 +272,17 @@ Pre-defined Phases
- The default for all builtin or custom directives unless otherwise specified.
-Calling Actions From Actions
+Calling Actions from Actions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.6
-Pyramid's configurator allows actions to be added during a commit-cycle as
-long as they are added to the current or a later ``order`` phase. This means
-that your custom action can defer decisions until commit-time and then do
-things like invoke :meth:`pyramid.config.Configurator.add_route`. It can also
-provide better conflict detection if your addon needs to call more than one
-other action.
+Pyramid's configurator allows actions to be added during a commit-cycle as long
+as they are added to the current or a later ``order`` phase. This means that
+your custom action can defer decisions until commit-time and then do things
+like invoke :meth:`pyramid.config.Configurator.add_route`. It can also provide
+better conflict detection if your addon needs to call more than one other
+action.
For example, let's make an addon that invokes ``add_route`` and ``add_view``,
but we want it to conflict with any other call to our addon:
@@ -304,12 +302,12 @@ but we want it to conflict with any other call to our addon:
config.action(('auto route', name), register, order=PHASE0_CONFIG)
Now someone else can use your addon and be informed if there is a conflict
-between this route and another, or two calls to ``add_auto_route``.
-Notice how we had to invoke our action **before** ``add_view`` or
-``add_route``. If we tried to invoke this afterward, the subsequent calls to
-``add_view`` and ``add_route`` would cause conflicts because that phase had
-already been executed, and the configurator cannot go back in time to add more
-views during that commit-cycle.
+between this route and another, or two calls to ``add_auto_route``. Notice how
+we had to invoke our action **before** ``add_view`` or ``add_route``. If we
+tried to invoke this afterward, the subsequent calls to ``add_view`` and
+``add_route`` would cause conflicts because that phase had already been
+executed, and the configurator cannot go back in time to add more views during
+that commit-cycle.
.. code-block:: python
:linenos:
@@ -341,16 +339,16 @@ All built-in Pyramid directives (such as
introspectables when called. For example, when you register a view via
``add_view``, the directive registers at least one introspectable: an
introspectable about the view registration itself, providing human-consumable
-values for the arguments it was passed. You can later use the introspection
-query system to determine whether a particular view uses a renderer, or
-whether a particular view is limited to a particular request method, or which
-routes a particular view is registered against. The Pyramid "debug toolbar"
-makes use of the introspection system in various ways to display information
-to Pyramid developers.
+values for the arguments passed into it. You can later use the introspection
+query system to determine whether a particular view uses a renderer, or whether
+a particular view is limited to a particular request method, or against which
+routes a particular view is registered. The Pyramid "debug toolbar" makes use
+of the introspection system in various ways to display information to Pyramid
+developers.
-Introspection values are set when a sequence of :term:`introspectable`
-objects is passed to the :meth:`~pyramid.config.Configurator.action` method.
-Here's an example of a directive which uses introspectables:
+Introspection values are set when a sequence of :term:`introspectable` objects
+is passed to the :meth:`~pyramid.config.Configurator.action` method. Here's an
+example of a directive which uses introspectables:
.. code-block:: python
:linenos:
@@ -370,9 +368,9 @@ Here's an example of a directive which uses introspectables:
config.add_directive('add_jammyjam', add_jammyjam)
If you notice, the above directive uses the ``introspectable`` attribute of a
-Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create
-an introspectable object. The introspectable object's constructor requires
-at least four arguments: the ``category_name``, the ``discriminator``, the
+Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create an
+introspectable object. The introspectable object's constructor requires at
+least four arguments: the ``category_name``, the ``discriminator``, the
``title``, and the ``type_name``.
The ``category_name`` is a string representing the logical category for this
@@ -392,19 +390,19 @@ The ``type_name`` is a value that can be used to subtype this introspectable
within its category for sorting and presentation purposes. It can be any
value.
-An introspectable is also dictionary-like. It can contain any set of
-key/value pairs, typically related to the arguments passed to its related
-directive. While the category_name, discriminator, title and type_name are
-*metadata* about the introspectable, the values provided as key/value pairs
+An introspectable is also dictionary-like. It can contain any set of key/value
+pairs, typically related to the arguments passed to its related directive.
+While the ``category_name``, ``discriminator``, ``title``, and ``type_name``
+are *metadata* about the introspectable, the values provided as key/value pairs
are the actual data provided by the introspectable. In the above example, we
set the ``value`` key to the value of the ``value`` argument passed to the
directive.
Our directive above mutates the introspectable, and passes it in to the
``action`` method as the first element of a tuple as the value of the
-``introspectable`` keyword argument. This associates this introspectable
-with the action. Introspection tools will then display this introspectable
-in their index.
+``introspectable`` keyword argument. This associates this introspectable with
+the action. Introspection tools will then display this introspectable in their
+index.
Introspectable Relationships
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -435,30 +433,29 @@ Two introspectables may have relationships between each other.
config.add_directive('add_jammyjam', add_jammyjam)
In the above example, the ``add_jammyjam`` directive registers two
-introspectables. The first is related to the ``value`` passed to the
-directive; the second is related to the ``template`` passed to the directive.
-If you believe a concept within a directive is important enough to have its
-own introspectable, you can cause the same directive to register more than
-one introspectable, registering one introspectable for the "main idea" and
-another for a related concept.
+introspectables: the first is related to the ``value`` passed to the directive,
+and the second is related to the ``template`` passed to the directive. If you
+believe a concept within a directive is important enough to have its own
+introspectable, you can cause the same directive to register more than one
+introspectable, registering one introspectable for the "main idea" and another
+for a related concept.
The call to ``intr.relate`` above
-(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments:
-a category name and a directive. The example above effectively indicates
-that the directive wishes to form a relationship between the ``intr``
-introspectable and the ``tmpl_intr`` introspectable; the arguments passed to
-``relate`` are the category name and discriminator of the ``tmpl_intr``
-introspectable.
-
-Relationships need not be made between two introspectables created by the
-same directive. Instead, a relationship can be formed between an
-introspectable created in one directive and another introspectable created in
-another by calling ``relate`` on either side with the other directive's
-category name and discriminator. An error will be raised at configuration
-commit time if you attempt to relate an introspectable with another
-nonexistent introspectable, however.
+(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments: a
+category name and a directive. The example above effectively indicates that
+the directive wishes to form a relationship between the ``intr`` introspectable
+and the ``tmpl_intr`` introspectable; the arguments passed to ``relate`` are
+the category name and discriminator of the ``tmpl_intr`` introspectable.
+
+Relationships need not be made between two introspectables created by the same
+directive. Instead a relationship can be formed between an introspectable
+created in one directive and another introspectable created in another by
+calling ``relate`` on either side with the other directive's category name and
+discriminator. An error will be raised at configuration commit time if you
+attempt to relate an introspectable with another nonexistent introspectable,
+however.
Introspectable relationships will show up in frontend system renderings of
-introspection values. For example, if a view registration names a route
-name, the introspectable related to the view callable will show a reference
-to the route to which it relates to and vice versa.
+introspection values. For example, if a view registration names a route name,
+the introspectable related to the view callable will show a reference to the
+route to which it relates and vice versa.
diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst
index 8462a9da7..d28eb341d 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -1,13 +1,13 @@
.. _extending_chapter:
-Extending An Existing :app:`Pyramid` Application
-===================================================
+Extending an Existing :app:`Pyramid` Application
+================================================
-If a :app:`Pyramid` developer has obeyed certain constraints while building
-an application, a third party should be able to change the application's
-behavior without needing to modify its source code. The behavior of a
-:app:`Pyramid` application that obeys certain constraints can be *overridden*
-or *extended* without modification.
+If a :app:`Pyramid` developer has obeyed certain constraints while building an
+application, a third party should be able to change the application's behavior
+without needing to modify its source code. The behavior of a :app:`Pyramid`
+application that obeys certain constraints can be *overridden* or *extended*
+without modification.
We'll define some jargon here for the benefit of identifying the parties
involved in such an effort.
@@ -16,10 +16,10 @@ Developer
The original application developer.
Integrator
- Another developer who wishes to reuse the application written by the
- original application developer in an unanticipated context. He may also
- wish to modify the original application without changing the original
- application's source code.
+ Another developer who wishes to reuse the application written by the original
+ application developer in an unanticipated context. They may also wish to
+ modify the original application without changing the original application's
+ source code.
The Difference Between "Extensible" and "Pluggable" Applications
----------------------------------------------------------------
@@ -27,31 +27,31 @@ The Difference Between "Extensible" and "Pluggable" Applications
Other web frameworks, such as :term:`Django`, advertise that they allow
developers to create "pluggable applications". They claim that if you create
an application in a certain way, it will be integratable in a sensible,
-structured way into another arbitrarily-written application or project
-created by a third-party developer.
+structured way into another arbitrarily-written application or project created
+by a third-party developer.
:app:`Pyramid`, as a platform, does not claim to provide such a feature. The
platform provides no guarantee that you can create an application and package
it up such that an arbitrary integrator can use it as a subcomponent in a
larger Pyramid application or project. Pyramid does not mandate the
constraints necessary for such a pattern to work satisfactorily. Because
-Pyramid is not very "opinionated", developers are able to use wildly
-different patterns and technologies to build an application. A given Pyramid
-application may happen to be reusable by a particular third party integrator,
-because the integrator and the original developer may share similar base
-technology choices (such as the use of a particular relational database or
-ORM). But the same application may not be reusable by a different developer,
-because he has made different technology choices which are incompatible with
-the original developer's.
+Pyramid is not very "opinionated", developers are able to use wildly different
+patterns and technologies to build an application. A given Pyramid application
+may happen to be reusable by a particular third party integrator because the
+integrator and the original developer may share similar base technology choices
+(such as the use of a particular relational database or ORM). But the same
+application may not be reusable by a different developer, because they have
+made different technology choices which are incompatible with the original
+developer's.
As a result, the concept of a "pluggable application" is left to layers built
above Pyramid, such as a "CMS" layer or "application server" layer. Such
-layers are apt to provide the necessary "opinions" (such as mandating a
-storage layer, a templating system, and a structured, well-documented pattern
-of registering that certain URLs map to certain bits of code) which makes the
-concept of a "pluggable application" possible. "Pluggable applications",
-thus, should not plug into Pyramid itself but should instead plug into a
-system written atop Pyramid.
+layers are apt to provide the necessary "opinions" (such as mandating a storage
+layer, a templating system, and a structured, well-documented pattern of
+registering that certain URLs map to certain bits of code) which makes the
+concept of a "pluggable application" possible. "Pluggable applications", thus,
+should not plug into Pyramid itself but should instead plug into a system
+written atop Pyramid.
Although it does not provide for "pluggable applications", Pyramid *does*
provide a rich set of mechanisms which allows for the extension of a single
@@ -64,13 +64,13 @@ Pyramid applications are *extensible*.
.. _building_an_extensible_app:
-Rules for Building An Extensible Application
+Rules for Building an Extensible Application
--------------------------------------------
There is only one rule you need to obey if you want to build a maximally
extensible :app:`Pyramid` application: as a developer, you should factor any
-overrideable :term:`imperative configuration` you've created into functions
-which can be used via :meth:`pyramid.config.Configurator.include` rather than
+overridable :term:`imperative configuration` you've created into functions
+which can be used via :meth:`pyramid.config.Configurator.include`, rather than
inlined as calls to methods of a :term:`Configurator` within the ``main``
function in your application's ``__init__.py``. For example, rather than:
@@ -84,8 +84,8 @@ function in your application's ``__init__.py``. For example, rather than:
config.add_view('myapp.views.view1', name='view1')
config.add_view('myapp.views.view2', name='view2')
-You should move the calls to ``add_view`` outside of the (non-reusable)
-``if __name__ == '__main__'`` block, and into a reusable function:
+You should move the calls to ``add_view`` outside of the (non-reusable) ``if
+__name__ == '__main__'`` block, and into a reusable function:
.. code-block:: python
:linenos:
@@ -100,13 +100,12 @@ You should move the calls to ``add_view`` outside of the (non-reusable)
config.add_view('myapp.views.view1', name='view1')
config.add_view('myapp.views.view2', name='view2')
-Doing this allows an integrator to maximally reuse the configuration
-statements that relate to your application by allowing him to selectively
-include or disinclude the configuration functions you've created from an
-"override package".
+Doing this allows an integrator to maximally reuse the configuration statements
+that relate to your application by allowing them to selectively include or
+exclude the configuration functions you've created from an "override package".
-Alternately, you can use :term:`ZCML` for the purpose of making configuration
-extensible and overrideable. :term:`ZCML` declarations that belong to an
+Alternatively you can use :term:`ZCML` for the purpose of making configuration
+extensible and overridable. :term:`ZCML` declarations that belong to an
application can be overridden and extended by integrators as necessary in a
similar fashion. If you use only :term:`ZCML` to configure your application,
it will automatically be maximally extensible without any manual effort. See
@@ -115,16 +114,15 @@ it will automatically be maximally extensible without any manual effort. See
Fundamental Plugpoints
~~~~~~~~~~~~~~~~~~~~~~
-The fundamental "plug points" of an application developed using
-:app:`Pyramid` are *routes*, *views*, and *assets*. Routes are declarations
-made using the :meth:`pyramid.config.Configurator.add_route` method. Views
-are declarations made using the :meth:`pyramid.config.Configurator.add_view`
-method. Assets are files that are
-accessed by :app:`Pyramid` using the :term:`pkg_resources` API such as static
-files and templates via a :term:`asset specification`. Other directives and
-configurator methods also deal in routes, views, and assets. For example, the
-``add_handler`` directive of the ``pyramid_handlers`` package adds a single
-route, and some number of views.
+The fundamental "plug points" of an application developed using :app:`Pyramid`
+are *routes*, *views*, and *assets*. Routes are declarations made using the
+:meth:`pyramid.config.Configurator.add_route` method. Views are declarations
+made using the :meth:`pyramid.config.Configurator.add_view` method. Assets are
+files that are accessed by :app:`Pyramid` using the :term:`pkg_resources` API
+such as static files and templates via a :term:`asset specification`. Other
+directives and configurator methods also deal in routes, views, and assets.
+For example, the ``add_handler`` directive of the ``pyramid_handlers`` package
+adds a single route and some number of views.
.. index::
single: extending an existing application
@@ -133,10 +131,9 @@ Extending an Existing Application
---------------------------------
The steps for extending an existing application depend largely on whether the
-application does or does not use configuration decorators and/or imperative
-code.
+application does or does not use configuration decorators or imperative code.
-If The Application Has Configuration Decorations
+If the Application Has Configuration Decorations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You've inherited a :app:`Pyramid` application which you'd like to extend or
@@ -155,9 +152,9 @@ registers more views or routes.
config.add_view('mypackage.views.myview', name='myview')
If you want to *override* configuration in the application, you *may* need to
-run :meth:`pyramid.config.Configurator.commit` after performing the scan of
-the original package, then add additional configuration that registers more
-views or routes which performs overrides.
+run :meth:`pyramid.config.Configurator.commit` after performing the scan of the
+original package, then add additional configuration that registers more views
+or routes which perform overrides.
.. code-block:: python
:linenos:
@@ -170,11 +167,11 @@ views or routes which performs overrides.
Once this is done, you should be able to extend or override the application
like any other (see :ref:`extending_the_application`).
-You can alternately just prevent a :term:`scan` from happening (by omitting
-any call to the :meth:`pyramid.config.Configurator.scan` method). This will
+You can alternatively just prevent a :term:`scan` from happening by omitting
+any call to the :meth:`pyramid.config.Configurator.scan` method. This will
cause the decorators attached to objects in the target application to do
-nothing. At this point, you will need to convert all the configuration done
-in decorators into equivalent imperative configuration or ZCML and add that
+nothing. At this point, you will need to convert all the configuration done in
+decorators into equivalent imperative configuration or ZCML, and add that
configuration or ZCML to a separate Python package as described in
:ref:`extending_the_application`.
@@ -183,37 +180,37 @@ configuration or ZCML to a separate Python package as described in
Extending the Application
~~~~~~~~~~~~~~~~~~~~~~~~~
-To extend or override the behavior of an existing application, you will need
-to create a new package which includes the configuration of the old package,
-and you'll perhaps need to create implementations of the types of things
-you'd like to override (such as views), which are referred to within the
-original package.
+To extend or override the behavior of an existing application, you will need to
+create a new package which includes the configuration of the old package, and
+you'll perhaps need to create implementations of the types of things you'd like
+to override (such as views), to which they are referred within the original
+package.
-The general pattern for extending an existing application looks something
-like this:
+The general pattern for extending an existing application looks something like
+this:
- Create a new Python package. The easiest way to do this is to create a new
:app:`Pyramid` application using the scaffold mechanism. See
:ref:`creating_a_project` for more information.
-- In the new package, create Python files containing views and other
- overridden elements, such as templates and static assets as necessary.
+- In the new package, create Python files containing views and other overridden
+ elements, such as templates and static assets as necessary.
- Install the new package into the same Python environment as the original
- application (e.g. ``$VENV/bin/python setup.py develop`` or
+ application (e.g., ``$VENV/bin/python setup.py develop`` or
``$VENV/bin/python setup.py install``).
- Change the ``main`` function in the new package's ``__init__.py`` to include
the original :app:`Pyramid` application's configuration functions via
:meth:`pyramid.config.Configurator.include` statements or a :term:`scan`.
-- Wire the new views and assets created in the new package up using
- imperative registrations within the ``main`` function of the
- ``__init__.py`` file of the new application. This wiring should happen
- *after* including the configuration functions of the old application.
- These registrations will extend or override any registrations performed by
- the original application. See :ref:`overriding_views`,
- :ref:`overriding_routes` and :ref:`overriding_resources`.
+- Wire the new views and assets created in the new package up using imperative
+ registrations within the ``main`` function of the ``__init__.py`` file of the
+ new application. This wiring should happen *after* including the
+ configuration functions of the old application. These registrations will
+ extend or override any registrations performed by the original application.
+ See :ref:`overriding_views`, :ref:`overriding_routes`, and
+ :ref:`overriding_resources`.
.. index::
pair: overriding; views
@@ -221,17 +218,17 @@ like this:
.. _overriding_views:
Overriding Views
-~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~
-The :term:`view configuration` declarations you make which *override*
+The :term:`view configuration` declarations that you make which *override*
application behavior will usually have the same :term:`view predicate`
-attributes as the original you wish to override. These ``<view>``
-declarations will point at "new" view code, in the override package you've
-created. The new view code itself will usually be cut-n-paste copies of view
-callables from the original application with slight tweaks.
+attributes as the original that you wish to override. These ``<view>``
+declarations will point at "new" view code in the override package that you've
+created. The new view code itself will usually be copy-and-paste copies of
+view callables from the original application with slight tweaks.
-For example, if the original application has the following
-``configure_views`` configuration method:
+For example, if the original application has the following ``configure_views``
+configuration method:
.. code-block:: python
:linenos:
@@ -254,13 +251,13 @@ configuration function:
config.include(configure_views)
config.add_view('theoverrideapp.views.theview', name='theview')
-In this case, the ``theoriginalapp.views.theview`` view will never be
-executed. Instead, a new view, ``theoverrideapp.views.theview`` will be
-executed instead, when request circumstances dictate.
+In this case, the ``theoriginalapp.views.theview`` view will never be executed.
+Instead, a new view, ``theoverrideapp.views.theview`` will be executed when
+request circumstances dictate.
A similar pattern can be used to *extend* the application with ``add_view``
-declarations. Just register a new view against some other set of predicates
-to make sure the URLs it implies are available on some other page rendering.
+declarations. Just register a new view against some other set of predicates to
+make sure the URLs it implies are available on some other page rendering.
.. index::
pair: overriding; routes
@@ -270,13 +267,13 @@ to make sure the URLs it implies are available on some other page rendering.
Overriding Routes
~~~~~~~~~~~~~~~~~
-Route setup is currently typically performed in a sequence of ordered calls
-to :meth:`~pyramid.config.Configurator.add_route`. Because these calls are
+Route setup is currently typically performed in a sequence of ordered calls to
+:meth:`~pyramid.config.Configurator.add_route`. Because these calls are
ordered relative to each other, and because this ordering is typically
important, you should retain their relative ordering when performing an
-override. Typically, this means *copying* all the ``add_route`` statements
-into the override package's file and changing them as necessary. Then
-disinclude any ``add_route`` statements from the original application.
+override. Typically this means *copying* all the ``add_route`` statements into
+the override package's file and changing them as necessary. Then exclude any
+``add_route`` statements from the original application.
.. index::
pair: overriding; assets
@@ -288,9 +285,8 @@ Overriding Assets
Assets are files on the filesystem that are accessible within a Python
*package*. An entire chapter is devoted to assets: :ref:`assets_chapter`.
-Within this chapter is a section named :ref:`overriding_assets_section`.
-This section of that chapter describes in detail how to override package
-assets with other assets by using the
-:meth:`pyramid.config.Configurator.override_asset` method. Add such
-``override_asset`` calls to your override package's ``__init__.py`` to
-perform overrides.
+Within this chapter is a section named :ref:`overriding_assets_section`. This
+section of that chapter describes in detail how to override package assets with
+other assets by using the :meth:`pyramid.config.Configurator.override_asset`
+method. Add such ``override_asset`` calls to your override package's
+``__init__.py`` to perform overrides.
diff --git a/docs/narr/hellotraversal.rst b/docs/narr/hellotraversal.rst
index 0a93b8f16..543e2171f 100644
--- a/docs/narr/hellotraversal.rst
+++ b/docs/narr/hellotraversal.rst
@@ -1,64 +1,60 @@
.. _hello_traversal_chapter:
Hello Traversal World
-======================
-
+=====================
.. index::
single: traversal quick example
-Traversal is an alternative to URL dispatch which allows Pyramid
-applications to map URLs to code.
+Traversal is an alternative to URL dispatch which allows Pyramid applications
+to map URLs to code.
-If code speaks louder than words, maybe this will help. Here is a
-single-file Pyramid application that uses traversal:
+If code speaks louder than words, maybe this will help. Here is a single-file
+Pyramid application that uses traversal:
.. literalinclude:: hellotraversal.py
:linenos:
-You may notice that this application is intentionally very similar to
-the "hello world" app from :doc:`firstapp`.
+You may notice that this application is intentionally very similar to the
+"hello world" application from :doc:`firstapp`.
On lines 5-6, we create a trivial :term:`resource` class that's just a
dictionary subclass.
-On lines 8-9, we hard-code a :term:`resource tree` in our :term:`root
-factory` function.
+On lines 8-9, we hard-code a :term:`resource tree` in our :term:`root factory`
+function.
-On lines 11-13 we define a single :term:`view callable` that can
-display a single instance of our Resource class, passed as the
-``context`` argument.
+On lines 11-13, we define a single :term:`view callable` that can display a
+single instance of our ``Resource`` class, passed as the ``context`` argument.
-The rest of the file sets up and serves our pyramid WSGI app. Line 18
-is where our view gets configured for use whenever the traversal ends
-with an instance of our Resource class.
+The rest of the file sets up and serves our :app:`Pyramid` WSGI app. Line 18
+is where our view gets configured for use whenever the traversal ends with an
+instance of our ``Resource`` class.
-Interestingly, there are no URLs explicitly configured in this
-application. Instead, the URL space is defined entirely by the keys in
-the resource tree.
+Interestingly, there are no URLs explicitly configured in this application.
+Instead, the URL space is defined entirely by the keys in the resource tree.
Example requests
----------------
-If this example is running on http://localhost:8080, and the user
-browses to http://localhost:8080/a/b, Pyramid will call
-``get_root(request)`` to get the root resource, then traverse the tree
-from there by key; starting from the root, it will find the child with
-key ``"a"``, then its child with key ``"b"``; then use that as the
-``context`` argument for calling ``hello_world_of_resources``.
+If this example is running on http://localhost:8080, and the user browses to
+http://localhost:8080/a/b, Pyramid will call ``get_root(request)`` to get the
+root resource, then traverse the tree from there by key; starting from the
+root, it will find the child with key ``"a"``, then its child with key ``"b"``;
+then use that as the ``context`` argument for calling
+``hello_world_of_resources``.
-Or, if the user browses to http://localhost:8080/ , Pyramid will
-stop at the root - the outermost Resource instance, in this case - and
-use that as the ``context`` argument to the same view.
+Or, if the user browses to http://localhost:8080/, Pyramid will stop at the
+root—the outermost ``Resource`` instance, in this case—and use that as the
+``context`` argument to the same view.
-Or, if the user browses to a key that doesn't exist in this resource
-tree, like http://localhost:8080/xyz or
-http://localhost:8080/a/b/c/d, the traversal will end by raising a
-KeyError, and Pyramid will turn that into a 404 HTTP response.
+Or, if the user browses to a key that doesn't exist in this resource tree, like
+http://localhost:8080/xyz or http://localhost:8080/a/b/c/d, the traversal will
+end by raising a KeyError, and Pyramid will turn that into a 404 HTTP response.
-A more complicated application could have many types of resources,
-with different view callables defined for each type, and even multiple
-views for each type.
+A more complicated application could have many types of resources, with
+different view callables defined for each type, and even multiple views for
+each type.
.. seealso::
@@ -66,4 +62,3 @@ views for each type.
For more about *why* you might use traversal, see
:doc:`muchadoabouttraversal`.
-
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 4fd7670b9..6aa1a99c2 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -14,12 +14,12 @@ in various ways.
Changing the Not Found View
---------------------------
-When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not
-Found View`, which is a :term:`view callable`. The default Not Found View
-can be overridden through application configuration.
+When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not Found
+View`, which is a :term:`view callable`. The default Not Found View can be
+overridden through application configuration.
-If your application uses :term:`imperative configuration`, you can replace
-the Not Found View by using the
+If your application uses :term:`imperative configuration`, you can replace the
+Not Found View by using the
:meth:`pyramid.config.Configurator.add_notfound_view` method:
.. code-block:: python
@@ -77,14 +77,14 @@ Views can carry predicates limiting their applicability. For example:
config = Configurator()
config.scan()
-The ``notfound_get`` view will be called when a view could not be found and
-the request method was ``GET``. The ``notfound_post`` view will be called
-when a view could not be found and the request method was ``POST``.
+The ``notfound_get`` view will be called when a view could not be found and the
+request method was ``GET``. The ``notfound_post`` view will be called when a
+view could not be found and the request method was ``POST``.
Like any other view, the Not Found View must accept at least a ``request``
-parameter, or both ``context`` and ``request``. The ``request`` is the
-current :term:`request` representing the denied action. The ``context`` (if
-used in the call signature) will be the instance of the
+parameter, or both ``context`` and ``request``. The ``request`` is the current
+:term:`request` representing the denied action. The ``context`` (if used in
+the call signature) will be the instance of the
:exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the view to
be called.
@@ -106,13 +106,13 @@ callable:
.. note::
- When a Not Found View callable is invoked, it is passed a
- :term:`request`. The ``exception`` attribute of the request will be an
- instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that
- caused the Not Found View to be called. The value of
- ``request.exception.message`` will be a value explaining why the Not Found
- error was raised. This message has different values depending whether the
- ``pyramid.debug_notfound`` environment setting is true or false.
+ When a Not Found View callable is invoked, it is passed a :term:`request`.
+ The ``exception`` attribute of the request will be an instance of the
+ :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not
+ Found View to be called. The value of ``request.exception.message`` will be
+ a value explaining why the Not Found exception was raised. This message has
+ different values depending on whether the ``pyramid.debug_notfound``
+ environment setting is true or false.
.. note::
@@ -124,9 +124,9 @@ callable:
.. warning::
- When a Not Found View callable accepts an argument list as
- described in :ref:`request_and_context_view_definitions`, the ``context``
- passed as the first argument to the view callable will be the
+ When a Not Found View callable accepts an argument list as described in
+ :ref:`request_and_context_view_definitions`, the ``context`` passed as the
+ first argument to the view callable will be the
:exc:`~pyramid.httpexceptions.HTTPNotFound` exception instance. If
available, the resource context will still be available as
``request.context``.
@@ -140,13 +140,13 @@ Changing the Forbidden View
---------------------------
When :app:`Pyramid` can't authorize execution of a view based on the
-:term:`authorization policy` in use, it invokes a :term:`forbidden view`.
-The default forbidden response has a 403 status code and is very plain, but
-the view which generates it can be overridden as necessary.
+:term:`authorization policy` in use, it invokes a :term:`forbidden view`. The
+default forbidden response has a 403 status code and is very plain, but the
+view which generates it can be overridden as necessary.
The :term:`forbidden view` callable is a view callable like any other. The
-:term:`view configuration` which causes it to be a "forbidden" view consists
-of using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the
+:term:`view configuration` which causes it to be a "forbidden" view consists of
+using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the
:class:`pyramid.view.forbidden_view_config` decorator.
For example, you can add a forbidden view by using the
@@ -181,14 +181,11 @@ as a forbidden view:
config.scan()
Like any other view, the forbidden view must accept at least a ``request``
-parameter, or both ``context`` and ``request``. If a forbidden view
-callable accepts both ``context`` and ``request``, the HTTP Exception is passed
-as context. The ``context`` as found by the router when view was
-denied (that you normally would expect) is available as
-``request.context``. The ``request`` is the current :term:`request`
-representing the denied action.
-
-
+parameter, or both ``context`` and ``request``. If a forbidden view callable
+accepts both ``context`` and ``request``, the HTTP Exception is passed as
+context. The ``context`` as found by the router when the view was denied (which
+you normally would expect) is available as ``request.context``. The
+``request`` is the current :term:`request` representing the denied action.
Here's some sample code that implements a minimal forbidden view:
@@ -203,15 +200,15 @@ Here's some sample code that implements a minimal forbidden view:
.. note::
- When a forbidden view callable is invoked, it is passed a
- :term:`request`. The ``exception`` attribute of the request will be an
- instance of the :exc:`~pyramid.httpexceptions.HTTPForbidden` exception
- that caused the forbidden view to be called. The value of
- ``request.exception.message`` will be a value explaining why the forbidden
- was raised and ``request.exception.result`` will be extended information
- about the forbidden exception. These messages have different values
- depending whether the ``pyramid.debug_authorization`` environment setting
- is true or false.
+ When a forbidden view callable is invoked, it is passed a :term:`request`.
+ The ``exception`` attribute of the request will be an instance of the
+ :exc:`~pyramid.httpexceptions.HTTPForbidden` exception that caused the
+ forbidden view to be called. The value of ``request.exception.message``
+ will be a value explaining why the forbidden exception was raised, and
+ ``request.exception.result`` will be extended information about the
+ forbidden exception. These messages have different values depending on
+ whether the ``pyramid.debug_authorization`` environment setting is true or
+ false.
.. index::
single: request factory
@@ -223,11 +220,11 @@ Changing the Request Factory
Whenever :app:`Pyramid` handles a request from a :term:`WSGI` server, it
creates a :term:`request` object based on the WSGI environment it has been
-passed. By default, an instance of the :class:`pyramid.request.Request`
-class is created to represent the request object.
+passed. By default, an instance of the :class:`pyramid.request.Request` class
+is created to represent the request object.
-The class (aka "factory") that :app:`Pyramid` uses to create a request object
-instance can be changed by passing a ``request_factory`` argument to the
+The class (a.k.a., "factory") that :app:`Pyramid` uses to create a request
+object instance can be changed by passing a ``request_factory`` argument to the
constructor of the :term:`configurator`. This argument can be either a
callable or a :term:`dotted Python name` representing a callable.
@@ -242,7 +239,7 @@ callable or a :term:`dotted Python name` representing a callable.
config = Configurator(request_factory=MyRequest)
If you're doing imperative configuration, and you'd rather do it after you've
-already constructed a :term:`configurator` it can also be registered via the
+already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_request_factory` method:
.. code-block:: python
@@ -262,19 +259,19 @@ already constructed a :term:`configurator` it can also be registered via the
.. _adding_request_method:
-Adding Methods or Properties to Request Object
-----------------------------------------------
+Adding Methods or Properties to a Request Object
+------------------------------------------------
.. versionadded:: 1.4.
Since each Pyramid application can only have one :term:`request` factory,
-:ref:`changing the request factory <changing_the_request_factory>`
-is not that extensible, especially if you want to build composable features
-(e.g., Pyramid add-ons and plugins).
+:ref:`changing the request factory <changing_the_request_factory>` is not that
+extensible, especially if you want to build composable features (e.g., Pyramid
+add-ons and plugins).
A lazy property can be registered to the request object via the
-:meth:`pyramid.config.Configurator.add_request_method` API. This allows you
-to specify a callable that will be available on the request object, but will not
+:meth:`pyramid.config.Configurator.add_request_method` API. This allows you to
+specify a callable that will be available on the request object, but will not
actually execute the function until accessed.
.. warning::
@@ -298,9 +295,10 @@ actually execute the function until accessed.
config.add_request_method(total)
config.add_request_method(prop, reify=True)
-In the above example, ``total`` is added as a method. However, ``prop`` is added
-as a property and its result is cached per-request by setting ``reify=True``.
-This way, we eliminate the overhead of running the function multiple times.
+In the above example, ``total`` is added as a method. However, ``prop`` is
+added as a property and its result is cached per-request by setting
+``reify=True``. This way, we eliminate the overhead of running the function
+multiple times.
>>> request.total(1, 2, 3)
6
@@ -354,18 +352,18 @@ We attach and cache an object named ``extra`` to the ``request`` object.
.. _changing_the_response_factory:
Changing the Response Factory
--------------------------------
+-----------------------------
.. versionadded:: 1.6
-Whenever :app:`Pyramid` returns a response from a view it creates a
+Whenever :app:`Pyramid` returns a response from a view, it creates a
:term:`response` object. By default, an instance of the
:class:`pyramid.response.Response` class is created to represent the response
object.
-The factory that :app:`Pyramid` uses to create a response object instance can be
-changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to
-the constructor of the :term:`configurator`. This argument can be either a
+The factory that :app:`Pyramid` uses to create a response object instance can
+be changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument
+to the constructor of the :term:`configurator`. This argument can be either a
callable or a :term:`dotted Python name` representing a callable.
The factory takes a single positional argument, which is a :term:`Request`
@@ -381,8 +379,8 @@ object. The argument may be ``None``.
config = Configurator(response_factory=lambda r: MyResponse())
-If you're doing imperative configuration, and you'd rather do it after you've
-already constructed a :term:`configurator` it can also be registered via the
+If you're doing imperative configuration and you'd rather do it after you've
+already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_response_factory` method:
.. code-block:: python
@@ -403,13 +401,13 @@ already constructed a :term:`configurator` it can also be registered via the
.. _beforerender_event:
-Using The Before Render Event
+Using the Before Render Event
-----------------------------
Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect
and modify the set of :term:`renderer globals` before they are passed to a
-:term:`renderer`. This event object iself has a dictionary-like interface
-that can be used for this purpose. For example:
+:term:`renderer`. This event object iself has a dictionary-like interface that
+can be used for this purpose. For example:
.. code-block:: python
:linenos:
@@ -421,22 +419,22 @@ that can be used for this purpose. For example:
def add_global(event):
event['mykey'] = 'foo'
-An object of this type is sent as an event just before a :term:`renderer`
-is invoked.
+An object of this type is sent as an event just before a :term:`renderer` is
+invoked.
-If a subscriber attempts to add a key that already exist in the renderer
+If a subscriber attempts to add a key that already exists in the renderer
globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced
because event subscribers do not possess any relative ordering. The set of
keys added to the renderer globals dictionary by all
-:class:`pyramid.events.BeforeRender` subscribers and renderer globals
-factories must be unique.
+:class:`pyramid.events.BeforeRender` subscribers and renderer globals factories
+must be unique.
The dictionary returned from the view is accessible through the
:attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender`
event.
-Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from
-your view callable, like so:
+Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from your
+view callable, like so:
.. code-block:: python
:linenos:
@@ -492,24 +490,23 @@ A response callback is a callable which accepts two positional parameters:
response.cache_control.max_age = 360
request.add_response_callback(cache_callback)
-No response callback is called if an unhandled exception happens in
-application code, or if the response object returned by a :term:`view
-callable` is invalid. Response callbacks *are*, however, invoked when a
-:term:`exception view` is rendered successfully: in such a case, the
-:attr:`request.exception` attribute of the request when it enters a response
-callback will be an exception object instead of its default value of
-``None``.
+No response callback is called if an unhandled exception happens in application
+code, or if the response object returned by a :term:`view callable` is invalid.
+Response callbacks *are*, however, invoked when a :term:`exception view` is
+rendered successfully. In such a case, the :attr:`request.exception` attribute
+of the request when it enters a response callback will be an exception object
+instead of its default value of ``None``.
Response callbacks are called in the order they're added
-(first-to-most-recently-added). All response callbacks are called *before*
-the :class:`~pyramid.events.NewResponse` event is sent. Errors raised by
-response callbacks are not handled specially. They will be propagated to the
-caller of the :app:`Pyramid` router application.
+(first-to-most-recently-added). All response callbacks are called *before* the
+:class:`~pyramid.events.NewResponse` event is sent. Errors raised by response
+callbacks are not handled specially. They will be propagated to the caller of
+the :app:`Pyramid` router application.
A response callback has a lifetime of a *single* request. If you want a
response callback to happen as the result of *every* request, you must
-re-register the callback into every new request (perhaps within a subscriber
-of a :class:`~pyramid.events.NewRequest` event).
+re-register the callback into every new request (perhaps within a subscriber of
+a :class:`~pyramid.events.NewRequest` event).
.. index::
single: finished callback
@@ -520,15 +517,15 @@ Using Finished Callbacks
------------------------
A :term:`finished callback` is a function that will be called unconditionally
-by the :app:`Pyramid` :term:`router` at the very end of request processing.
-A finished callback can be used to perform an action at the end of a request
+by the :app:`Pyramid` :term:`router` at the very end of request processing. A
+finished callback can be used to perform an action at the end of a request
unconditionally.
The :meth:`pyramid.request.Request.add_finished_callback` method is used to
register a finished callback.
-A finished callback is a callable which accepts a single positional
-parameter: ``request``. For example:
+A finished callback is a callable which accepts a single positional parameter:
+``request``. For example:
.. code-block:: python
:linenos:
@@ -543,29 +540,27 @@ parameter: ``request``. For example:
request.add_finished_callback(log_callback)
Finished callbacks are called in the order they're added
-(first-to-most-recently-added). Finished callbacks (unlike a
-:term:`response callback`) are *always* called, even if an exception
-happens in application code that prevents a response from being
-generated.
-
-The set of finished callbacks associated with a request are called *very
-late* in the processing of that request; they are essentially the very last
-thing called by the :term:`router` before a request "ends". They are called
-after response processing has already occurred in a top-level ``finally:``
-block within the router request processing code. As a result, mutations
-performed to the ``request`` provided to a finished callback will have no
-meaningful effect, because response processing will have already occurred,
-and the request's scope will expire almost immediately after all finished
-callbacks have been processed.
-
-Errors raised by finished callbacks are not handled specially. They
-will be propagated to the caller of the :app:`Pyramid` router
-application.
+(first-to-most-recently-added). Finished callbacks (unlike a :term:`response
+callback`) are *always* called, even if an exception happens in application
+code that prevents a response from being generated.
+
+The set of finished callbacks associated with a request are called *very late*
+in the processing of that request; they are essentially the very last thing
+called by the :term:`router` before a request "ends". They are called after
+response processing has already occurred in a top-level ``finally:`` block
+within the router request processing code. As a result, mutations performed to
+the ``request`` provided to a finished callback will have no meaningful effect,
+because response processing will have already occurred, and the request's scope
+will expire almost immediately after all finished callbacks have been
+processed.
+
+Errors raised by finished callbacks are not handled specially. They will be
+propagated to the caller of the :app:`Pyramid` router application.
A finished callback has a lifetime of a *single* request. If you want a
finished callback to happen as the result of *every* request, you must
-re-register the callback into every new request (perhaps within a subscriber
-of a :class:`~pyramid.events.NewRequest` event).
+re-register the callback into every new request (perhaps within a subscriber of
+a :class:`~pyramid.events.NewRequest` event).
.. index::
single: traverser
@@ -577,8 +572,8 @@ Changing the Traverser
The default :term:`traversal` algorithm that :app:`Pyramid` uses is explained
in :ref:`traversal_algorithm`. Though it is rarely necessary, this default
-algorithm can be swapped out selectively for a different traversal pattern
-via configuration.
+algorithm can be swapped out selectively for a different traversal pattern via
+configuration.
.. code-block:: python
:linenos:
@@ -624,10 +619,10 @@ that implements the following interface:
More than one traversal algorithm can be active at the same time. For
instance, if your :term:`root factory` returns more than one type of object
-conditionally, you could claim that an alternate traverser adapter is "for"
+conditionally, you could claim that an alternative traverser adapter is "for"
only one particular class or interface. When the root factory returned an
object that implemented that class or interface, a custom traverser would be
-used. Otherwise, the default traverser would be used. For example:
+used. Otherwise the default traverser would be used. For example:
.. code-block:: python
:linenos:
@@ -639,13 +634,13 @@ used. Otherwise, the default traverser would be used. For example:
config.add_traverser(Traverser, MyRoot)
If the above stanza was added to a Pyramid ``__init__.py`` file's ``main``
-function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only
-when the application :term:`root factory` returned an instance of the
+function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only when
+the application :term:`root factory` returned an instance of the
``myapp.resources.MyRoot`` object. Otherwise it would use the default
:app:`Pyramid` traverser to do traversal.
.. index::
- single: url generator
+ single: URL generator
.. _changing_resource_url:
@@ -655,9 +650,8 @@ Changing How :meth:`pyramid.request.Request.resource_url` Generates a URL
When you add a traverser as described in :ref:`changing_the_traverser`, it's
often convenient to continue to use the
:meth:`pyramid.request.Request.resource_url` API. However, since the way
-traversal is done will have been modified, the URLs it generates by default
-may be incorrect when used against resources derived from your custom
-traverser.
+traversal is done will have been modified, the URLs it generates by default may
+be incorrect when used against resources derived from your custom traverser.
If you've added a traverser, you can change how
:meth:`~pyramid.request.Request.resource_url` generates a URL for a specific
@@ -674,13 +668,13 @@ For example:
config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)
-In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will
-be used to provide services to :meth:`~pyramid.request.Request.resource_url`
-any time the :term:`resource` passed to ``resource_url`` is of the class
+In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be
+used to provide services to :meth:`~pyramid.request.Request.resource_url` any
+time the :term:`resource` passed to ``resource_url`` is of the class
``myapp.resources.MyRoot``. The ``resource_iface`` argument ``MyRoot``
represents the type of interface that must be possessed by the resource for
this resource url factory to be found. If the ``resource_iface`` argument is
-omitted, this resource url adapter will be used for *all* resources.
+omitted, this resource URL adapter will be used for *all* resources.
The API that must be implemented by a class that provides
:class:`~pyramid.interfaces.IResourceURL` is as follows:
@@ -693,8 +687,8 @@ The API that must be implemented by a class that provides
resource
"""
def __init__(self, resource, request):
- """ Accept the resource and request and set self.physical_path and
- self.virtual_path"""
+ """ Accept the resource and request and set self.physical_path and
+ self.virtual_path """
self.virtual_path = some_function_of(resource, request)
self.physical_path = some_other_function_of(resource, request)
@@ -703,7 +697,8 @@ The default context URL generator is available for perusal as the class
<https://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of the
:term:`Pylons` GitHub Pyramid repository.
-See :meth:`pyramid.config.add_resource_url_adapter` for more information.
+See :meth:`pyramid.config.Configurator.add_resource_url_adapter` for more
+information.
.. index::
single: IResponse
@@ -721,25 +716,24 @@ callable on a per-type basis by using a hook involving
:meth:`pyramid.config.Configurator.add_response_adapter` or the
:class:`~pyramid.response.response_adapter` decorator.
-Pyramid, in various places, adapts the result of calling a view callable to
-the :class:`~pyramid.interfaces.IResponse` interface to ensure that the
-object returned by the view callable is a "true" response object. The vast
-majority of time, the result of this adaptation is the result object itself,
-as view callables written by "civilians" who read the narrative documentation
-contained in this manual will always return something that implements the
-:class:`~pyramid.interfaces.IResponse` interface. Most typically, this will
-be an instance of the :class:`pyramid.response.Response` class or a subclass.
-If a civilian returns a non-Response object from a view callable that isn't
-configured to use a :term:`renderer`, he will typically expect the router to
+Pyramid, in various places, adapts the result of calling a view callable to the
+:class:`~pyramid.interfaces.IResponse` interface to ensure that the object
+returned by the view callable is a "true" response object. The vast majority
+of time, the result of this adaptation is the result object itself, as view
+callables written by "civilians" who read the narrative documentation contained
+in this manual will always return something that implements the
+:class:`~pyramid.interfaces.IResponse` interface. Most typically, this will be
+an instance of the :class:`pyramid.response.Response` class or a subclass. If a
+civilian returns a non-Response object from a view callable that isn't
+configured to use a :term:`renderer`, they will typically expect the router to
raise an error. However, you can hook Pyramid in such a way that users can
return arbitrary values from a view callable by providing an adapter which
converts the arbitrary return value into something that implements
:class:`~pyramid.interfaces.IResponse`.
For example, if you'd like to allow view callables to return bare string
-objects (without requiring a :term:`renderer` to convert a string to a
-response object), you can register an adapter which converts the string to a
-Response:
+objects (without requiring a :term:`renderer` to convert a string to a response
+object), you can register an adapter which converts the string to a Response:
.. code-block:: python
:linenos:
@@ -754,9 +748,9 @@ Response:
config.add_response_adapter(string_response_adapter, str)
-Likewise, if you want to be able to return a simplified kind of response
-object from view callables, you can use the IResponse hook to register an
-adapter to the more complex IResponse interface:
+Likewise, if you want to be able to return a simplified kind of response object
+from view callables, you can use the IResponse hook to register an adapter to
+the more complex IResponse interface:
.. code-block:: python
:linenos:
@@ -777,7 +771,7 @@ adapter to the more complex IResponse interface:
If you want to implement your own Response object instead of using the
:class:`pyramid.response.Response` object in any capacity at all, you'll have
-to make sure the object implements every attribute and method outlined in
+to make sure that the object implements every attribute and method outlined in
:class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses
``zope.interface.implementer(IResponse)`` as a class decorator.
@@ -789,7 +783,7 @@ to make sure the object implements every attribute and method outlined in
@implementer(IResponse)
class MyResponse(object):
- # ... an implementation of every method and attribute
+ # ... an implementation of every method and attribute
# documented in IResponse should follow ...
When an alternate response object implementation is returned by a view
@@ -804,8 +798,8 @@ startup time, as by their nature, instances of this class (and instances of
subclasses of the class) will natively provide IResponse. The adapter
registered for ``webob.Response`` simply returns the response object.
-Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`,
-you can use the :class:`pyramid.response.response_adapter` decorator:
+Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, you
+can use the :class:`pyramid.response.response_adapter` decorator:
.. code-block:: python
:linenos:
@@ -841,31 +835,29 @@ callables by employing a :term:`view mapper`.
A view mapper is an object that accepts a set of keyword arguments and which
returns a callable. The returned callable is called with the :term:`view
-callable` object. The returned callable should itself return another
-callable which can be called with the "internal calling protocol" ``(context,
+callable` object. The returned callable should itself return another callable
+which can be called with the "internal calling protocol" ``(context,
request)``.
You can use a view mapper in a number of ways:
-- by setting a ``__view_mapper__`` attribute (which is the view mapper
- object) on the view callable itself
+- by setting a ``__view_mapper__`` attribute (which is the view mapper object)
+ on the view callable itself
-- by passing the mapper object to
- :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator
- equivalents) as the ``mapper`` argument.
+- by passing the mapper object to :meth:`pyramid.config.Configurator.add_view`
+ (or its declarative and decorator equivalents) as the ``mapper`` argument
-- by registering a *default* view mapper.
+- by registering a *default* view mapper
Here's an example of a view mapper that emulates (somewhat) a Pylons
"controller". The mapper is initialized with some keyword arguments. Its
``__call__`` method accepts the view object (which will be a class). It uses
-the ``attr`` keyword argument it is passed to determine which attribute
-should be used as an action method. The wrapper method it returns accepts
-``(context, request)`` and returns the result of calling the action method
-with keyword arguments implied by the :term:`matchdict` after popping the
-``action`` out of it. This somewhat emulates the Pylons style of calling
-action methods with routing parameters pulled out of the route matching dict
-as keyword arguments.
+the ``attr`` keyword argument it is passed to determine which attribute should
+be used as an action method. The wrapper method it returns accepts ``(context,
+request)`` and returns the result of calling the action method with keyword
+arguments implied by the :term:`matchdict` after popping the ``action`` out of
+it. This somewhat emulates the Pylons style of calling action methods with
+routing parameters pulled out of the route matching dict as keyword arguments.
.. code-block:: python
:linenos:
@@ -917,8 +909,8 @@ The :meth:`pyramid.config.Configurator.set_view_mapper` method can be used to
set a *default* view mapper (overriding the superdefault view mapper used by
Pyramid itself).
-A *single* view registration can use a view mapper by passing the mapper as
-the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
+A *single* view registration can use a view mapper by passing the mapper as the
+``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
.. index::
single: configuration decorator
@@ -928,14 +920,14 @@ the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`.
Registering Configuration Decorators
------------------------------------
-Decorators such as :class:`~pyramid.view.view_config` don't change the
-behavior of the functions or classes they're decorating. Instead, when a
-:term:`scan` is performed, a modified version of the function or class is
-registered with :app:`Pyramid`.
+Decorators such as :class:`~pyramid.view.view_config` don't change the behavior
+of the functions or classes they're decorating. Instead when a :term:`scan` is
+performed, a modified version of the function or class is registered with
+:app:`Pyramid`.
You may wish to have your own decorators that offer such behaviour. This is
-possible by using the :term:`Venusian` package in the same way that it is
-used by :app:`Pyramid`.
+possible by using the :term:`Venusian` package in the same way that it is used
+by :app:`Pyramid`.
By way of example, let's suppose you want to write a decorator that registers
the function it wraps with a :term:`Zope Component Architecture` "utility"
@@ -945,8 +937,7 @@ available once your application's configuration is at least partially
completed. A normal decorator would fail as it would be executed before the
configuration had even begun.
-However, using :term:`Venusian`, the decorator could be written as
-follows:
+However, using :term:`Venusian`, the decorator could be written as follows:
.. code-block:: python
:linenos:
@@ -968,18 +959,17 @@ follows:
venusian.attach(wrapped, self.register)
return wrapped
-This decorator could then be used to register functions throughout
-your code:
+This decorator could then be used to register functions throughout your code:
.. code-block:: python
:linenos:
@registerFunction('/some/path')
def my_function():
- do_stuff()
+ do_stuff()
-However, the utility would only be looked up when a :term:`scan` was
-performed, enabling you to set up the utility in advance:
+However, the utility would only be looked up when a :term:`scan` was performed,
+enabling you to set up the utility in advance:
.. code-block:: python
:linenos:
@@ -994,10 +984,10 @@ performed, enabling you to set up the utility in advance:
class UtilityImplementation:
def __init__(self):
- self.registrations = {}
+ self.registrations = {}
def register(self, path, callable_):
- self.registrations[path] = callable_
+ self.registrations[path] = callable_
if __name__ == '__main__':
config = Configurator()
@@ -1021,27 +1011,27 @@ Registering Tweens
A :term:`tween` (a contraction of the word "between") is a bit of code that
sits between the Pyramid router's main request handling function and the
upstream WSGI component that uses :app:`Pyramid` as its "app". This is a
-feature that may be used by Pyramid framework extensions, to provide, for
+feature that may be used by Pyramid framework extensions to provide, for
example, Pyramid-specific view timing support bookkeeping code that examines
exceptions before they are returned to the upstream WSGI application. Tweens
-behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of
+behave a bit like :term:`WSGI` :term:`middleware`, but they have the benefit of
running in a context in which they have access to the Pyramid :term:`request`,
-:term:`response` and :term:`application registry` as well as the Pyramid
+:term:`response`, and :term:`application registry`, as well as the Pyramid
rendering machinery.
Creating a Tween
~~~~~~~~~~~~~~~~
-To create a tween, you must write a "tween factory". A tween factory
-must be a globally importable callable which accepts two arguments:
-``handler`` and ``registry``. ``handler`` will be either the main
-Pyramid request handling function or another tween. ``registry`` will be the
-Pyramid :term:`application registry` represented by this Configurator. A
-tween factory must return the tween (a callable object) when it is called.
+To create a tween, you must write a "tween factory". A tween factory must be a
+globally importable callable which accepts two arguments: ``handler`` and
+``registry``. ``handler`` will be either the main Pyramid request handling
+function or another tween. ``registry`` will be the Pyramid :term:`application
+registry` represented by this Configurator. A tween factory must return the
+tween (a callable object) when it is called.
A tween is called with a single argument, ``request``, which is the
-:term:`request` created by Pyramid's router when it receives a WSGI request.
-A tween should return a :term:`response`, usually the one generated by the
+:term:`request` created by Pyramid's router when it receives a WSGI request. A
+tween should return a :term:`response`, usually the one generated by the
downstream Pyramid application.
You can write the tween factory as a simple closure-returning function:
@@ -1089,14 +1079,14 @@ method:
return response
-You should avoid mutating any state on the tween instance. The tween is
-invoked once per request and any shared mutable state needs to be carefully
-handled to avoid any race conditions.
+You should avoid mutating any state on the tween instance. The tween is invoked
+once per request and any shared mutable state needs to be carefully handled to
+avoid any race conditions.
The closure style performs slightly better and enables you to conditionally
omit the tween from the request processing pipeline (see the following timing
tween example), whereas the class style makes it easier to have shared mutable
-state, and it allows subclassing.
+state and allows subclassing.
Here's a complete example of a tween that logs the time spent processing each
request:
@@ -1131,13 +1121,12 @@ request:
In the above example, the tween factory defines a ``timing_tween`` tween and
returns it if ``asbool(registry.settings.get('do_timing'))`` is true. It
-otherwise simply returns the handler it was given. The ``registry.settings``
-attribute is a handle to the deployment settings provided by the user
-(usually in an ``.ini`` file). In this case, if the user has defined a
-``do_timing`` setting, and that setting is ``True``, the user has said she
-wants to do timing, so the tween factory returns the timing tween; it
-otherwise just returns the handler it has been provided, preventing any
-timing.
+otherwise simply returns the handler which it was given. The
+``registry.settings`` attribute is a handle to the deployment settings provided
+by the user (usually in an ``.ini`` file). In this case, if the user has
+defined a ``do_timing`` setting and that setting is ``True``, the user has said
+they want to do timing, so the tween factory returns the timing tween; it
+otherwise just returns the handler it has been provided, preventing any timing.
The example timing tween simply records the start time, calls the downstream
handler, logs the number of seconds consumed by the downstream handler, and
@@ -1163,29 +1152,28 @@ Pyramid application:
Note that you must use a :term:`dotted Python name` as the first argument to
:meth:`pyramid.config.Configurator.add_tween`; this must point at a tween
factory. You cannot pass the tween factory object itself to the method: it
-must be :term:`dotted Python name` that points to a globally importable
-object. In the above example, we assume that a ``timing_tween_factory``
-tween factory was defined in a module named ``myapp.tweens``, so the tween
-factory is importable as ``myapp.tweens.timing_tween_factory``.
-
-When you use :meth:`pyramid.config.Configurator.add_tween`, you're
-instructing the system to use your tween factory at startup time unless the
-user has provided an explicit tween list in his configuration. This is
-what's meant by an "implicit" tween. A user can always elect to supply an
-explicit tween list, reordering or disincluding implicitly added tweens. See
+must be :term:`dotted Python name` that points to a globally importable object.
+In the above example, we assume that a ``timing_tween_factory`` tween factory
+was defined in a module named ``myapp.tweens``, so the tween factory is
+importable as ``myapp.tweens.timing_tween_factory``.
+
+When you use :meth:`pyramid.config.Configurator.add_tween`, you're instructing
+the system to use your tween factory at startup time unless the user has
+provided an explicit tween list in their configuration. This is what's meant
+by an "implicit" tween. A user can always elect to supply an explicit tween
+list, reordering or disincluding implicitly added tweens. See
:ref:`explicit_tween_ordering` for more information about explicit tween
ordering.
-If more than one call to :meth:`pyramid.config.Configurator.add_tween` is
-made within a single application configuration, the tweens will be chained
-together at application startup time. The *first* tween factory added via
-``add_tween`` will be called with the Pyramid exception view tween factory as
-its ``handler`` argument, then the tween factory added directly after that
-one will be called with the result of the first tween factory as its
-``handler`` argument, and so on, ad infinitum until all tween factories have
-been called. The Pyramid router will use the outermost tween produced by this
-chain (the tween generated by the very last tween factory added) as its
-request handler function. For example:
+If more than one call to :meth:`pyramid.config.Configurator.add_tween` is made
+within a single application configuration, the tweens will be chained together
+at application startup time. The *first* tween factory added via ``add_tween``
+will be called with the Pyramid exception view tween factory as its ``handler``
+argument, then the tween factory added directly after that one will be called
+with the result of the first tween factory as its ``handler`` argument, and so
+on, ad infinitum until all tween factories have been called. The Pyramid router
+will use the outermost tween produced by this chain (the tween generated by the
+very last tween factory added) as its request handler function. For example:
.. code-block:: python
:linenos:
@@ -1196,8 +1184,7 @@ request handler function. For example:
config.add_tween('myapp.tween_factory1')
config.add_tween('myapp.tween_factory2')
-The above example will generate an implicit tween chain that looks like
-this::
+The above example will generate an implicit tween chain that looks like this::
INGRESS (implicit)
myapp.tween_factory2
@@ -1211,37 +1198,36 @@ Suggesting Implicit Tween Ordering
By default, as described above, the ordering of the chain is controlled
entirely by the relative ordering of calls to
:meth:`pyramid.config.Configurator.add_tween`. However, the caller of
-add_tween can provide an optional hint that can influence the implicit tween
-chain ordering by supplying ``under`` or ``over`` (or both) arguments to
-:meth:`~pyramid.config.Configurator.add_tween`. These hints are only
-used when an explicit tween ordering is not used. See
-:ref:`explicit_tween_ordering` for a description of how to set an explicit
-tween ordering.
+``add_tween`` can provide an optional hint that can influence the implicit
+tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to
+:meth:`~pyramid.config.Configurator.add_tween`. These hints are only used when
+an explicit tween ordering is not used. See :ref:`explicit_tween_ordering` for
+a description of how to set an explicit tween ordering.
Allowable values for ``under`` or ``over`` (or both) are:
-- ``None`` (the default).
+- ``None`` (the default),
-- A :term:`dotted Python name` to a tween factory: a string representing the
- predicted dotted name of a tween factory added in a call to ``add_tween``
- in the same configuration session.
+- a :term:`dotted Python name` to a tween factory: a string representing the
+ predicted dotted name of a tween factory added in a call to ``add_tween`` in
+ the same configuration session,
-- One of the constants :attr:`pyramid.tweens.MAIN`,
- :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`.
+- one of the constants :attr:`pyramid.tweens.MAIN`,
+ :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`, or
-- An iterable of any combination of the above. This allows the user to specify
+- an iterable of any combination of the above. This allows the user to specify
fallbacks if the desired tween is not included, as well as compatibility
with multiple other tweens.
-Effectively, ``over`` means "closer to the request ingress than" and
-``under`` means "closer to the main Pyramid application than".
-You can think of an onion with outer layers over the inner layers,
-the application being under all the layers at the center.
+Effectively, ``over`` means "closer to the request ingress than" and ``under``
+means "closer to the main Pyramid application than". You can think of an onion
+with outer layers over the inner layers, the application being under all the
+layers at the center.
For example, the following call to
-:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the
-tween factory represented by ``myapp.tween_factory`` directly 'above' (in
-``ptweens`` order) the main Pyramid request handler.
+:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the tween
+factory represented by ``myapp.tween_factory`` directly "above" (in ``ptweens``
+order) the main Pyramid request handler.
.. code-block:: python
:linenos:
@@ -1250,8 +1236,7 @@ tween factory represented by ``myapp.tween_factory`` directly 'above' (in
config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)
-The above example will generate an implicit tween chain that looks like
-this::
+The above example will generate an implicit tween chain that looks like this::
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
@@ -1259,9 +1244,8 @@ this::
MAIN (implicit)
Likewise, calling the following call to
-:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this
-tween factory 'above' the main handler but 'below' a separately added tween
-factory:
+:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this tween
+factory "above" the main handler but "below" a separately added tween factory:
.. code-block:: python
:linenos:
@@ -1274,8 +1258,7 @@ factory:
over=pyramid.tweens.MAIN,
under='myapp.tween_factory1')
-The above example will generate an implicit tween chain that looks like
-this::
+The above example will generate an implicit tween chain that looks like this::
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
@@ -1288,28 +1271,28 @@ Specifying neither ``over`` nor ``under`` is equivalent to specifying
If all options for ``under`` (or ``over``) cannot be found in the current
configuration, it is an error. If some options are specified purely for
-compatibilty with other tweens, just add a fallback of MAIN or INGRESS.
-For example, ``under=('someothertween', 'someothertween2', INGRESS)``.
-This constraint will require the tween to be located under both the
-'someothertween' tween, the 'someothertween2' tween, and INGRESS. If any of
-these is not in the current configuration, this constraint will only organize
-itself based on the tweens that are present.
+compatibilty with other tweens, just add a fallback of ``MAIN`` or ``INGRESS``.
+For example, ``under=('someothertween', 'someothertween2', INGRESS)``. This
+constraint will require the tween to be located under the ``someothertween``
+tween, the ``someothertween2`` tween, and ``INGRESS``. If any of these is not
+in the current configuration, this constraint will only organize itself based
+on the tweens that are present.
.. _explicit_tween_ordering:
Explicit Tween Ordering
~~~~~~~~~~~~~~~~~~~~~~~
-Implicit tween ordering is obviously only best-effort. Pyramid will attempt
-to provide an implicit order of tweens as best it can using hints provided by
-calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's
-only best-effort, if very precise tween ordering is required, the only
-surefire way to get it is to use an explicit tween order. The deploying user
-can override the implicit tween inclusion and ordering implied by calls to
+Implicit tween ordering is obviously only best-effort. Pyramid will attempt to
+provide an implicit order of tweens as best it can using hints provided by
+calls to :meth:`~pyramid.config.Configurator.add_tween`. But because it's only
+best-effort, if very precise tween ordering is required, the only surefire way
+to get it is to use an explicit tween order. The deploying user can override
+the implicit tween inclusion and ordering implied by calls to
:meth:`~pyramid.config.Configurator.add_tween` entirely by using the
``pyramid.tweens`` settings value. When used, this settings value must be a
-list of Python dotted names which will override the ordering (and inclusion)
-of tween factories in the implicit tween chain. For example:
+list of Python dotted names which will override the ordering (and inclusion) of
+tween factories in the implicit tween chain. For example:
.. code-block:: ini
:linenos:
@@ -1327,19 +1310,19 @@ of tween factories in the implicit tween chain. For example:
In the above configuration, calls made during configuration to
:meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is
telling the system to use the tween factories he has listed in the
-``pyramid.tweens`` configuration setting (each is a :term:`dotted Python
-name` which points to a tween factory) instead of any tween factories added
-via :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory
-in the ``pyramid.tweens`` list will be used as the producer of the effective
+``pyramid.tweens`` configuration setting (each is a :term:`dotted Python name`
+which points to a tween factory) instead of any tween factories added via
+:meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory in
+the ``pyramid.tweens`` list will be used as the producer of the effective
:app:`Pyramid` request handling function; it will wrap the tween factory
-declared directly "below" it, ad infinitum. The "main" Pyramid request
-handler is implicit, and always "at the bottom".
+declared directly "below" it, ad infinitum. The "main" Pyramid request handler
+is implicit, and always "at the bottom".
.. note::
- Pyramid's own :term:`exception view` handling logic is implemented
- as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`.
- If Pyramid exception view handling is desired, and tween factories are
+ Pyramid's own :term:`exception view` handling logic is implemented as a
+ tween factory function: :func:`pyramid.tweens.excview_tween_factory`. If
+ Pyramid exception view handling is desired, and tween factories are
specified via the ``pyramid.tweens`` configuration setting, the
:func:`pyramid.tweens.excview_tween_factory` function must be added to the
``pyramid.tweens`` configuration setting list explicitly. If it is not
@@ -1348,30 +1331,30 @@ handler is implicit, and always "at the bottom".
Tween Conflicts and Ordering Cycles
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Pyramid will prevent the same tween factory from being added to the tween
-chain more than once using configuration conflict detection. If you wish to
-add the same tween factory more than once in a configuration, you should
-either: a) use a tween factory that is a separate globally importable
-instance object from the factory that it conflicts with b) use a function or
-class as a tween factory with the same logic as the other tween factory it
-conflicts with but with a different ``__name__`` attribute or c) call
+Pyramid will prevent the same tween factory from being added to the tween chain
+more than once using configuration conflict detection. If you wish to add the
+same tween factory more than once in a configuration, you should either: (a)
+use a tween factory that is a separate globally importable instance object from
+the factory that it conflicts with; (b) use a function or class as a tween
+factory with the same logic as the other tween factory it conflicts with, but
+with a different ``__name__`` attribute; or (c) call
:meth:`pyramid.config.Configurator.commit` between calls to
:meth:`pyramid.config.Configurator.add_tween`.
If a cycle is detected in implicit tween ordering when ``over`` and ``under``
-are used in any call to "add_tween", an exception will be raised at startup
+are used in any call to ``add_tween``, an exception will be raised at startup
time.
Displaying Tween Ordering
~~~~~~~~~~~~~~~~~~~~~~~~~
-The ``ptweens`` command-line utility can be used to report the current
-implict and explicit tween chains used by an application. See
+The ``ptweens`` command-line utility can be used to report the current implict
+and explicit tween chains used by an application. See
:ref:`displaying_tweens`.
.. _registering_thirdparty_predicates:
-Adding A Third Party View, Route, or Subscriber Predicate
+Adding a Third Party View, Route, or Subscriber Predicate
---------------------------------------------------------
.. versionadded:: 1.4
@@ -1381,10 +1364,10 @@ Adding A Third Party View, Route, or Subscriber Predicate
View and Route Predicates
~~~~~~~~~~~~~~~~~~~~~~~~~
-View and route predicates used during configuration allow you to narrow the
-set of circumstances under which a view or route will match. For example,
-the ``request_method`` view predicate can be used to ensure a view callable
-is only invoked when the request's method is ``POST``:
+View and route predicates used during configuration allow you to narrow the set
+of circumstances under which a view or route will match. For example, the
+``request_method`` view predicate can be used to ensure a view callable is only
+invoked when the request's method is ``POST``:
.. code-block:: python
@@ -1398,9 +1381,9 @@ Likewise, a similar predicate can be used as a *route* predicate:
config.add_route('name', '/foo', request_method='POST')
-Many other built-in predicates exists (``request_param``, and others). You
-can add third-party predicates to the list of available predicates by using
-one of :meth:`pyramid.config.Configurator.add_view_predicate` or
+Many other built-in predicates exists (``request_param``, and others). You can
+add third-party predicates to the list of available predicates by using one of
+:meth:`pyramid.config.Configurator.add_view_predicate` or
:meth:`pyramid.config.Configurator.add_route_predicate`. The former adds a
view predicate, the latter a route predicate.
@@ -1428,7 +1411,7 @@ the name, is a string representing the name that is expected to be passed to
The second argument is a view or route predicate factory, or a :term:`dotted
Python name` which refers to a view or route predicate factory. A view or
route predicate factory is most often a class with a constructor
-(``__init__``), a ``text`` method, a ``phash`` method and a ``__call__``
+(``__init__``), a ``text`` method, a ``phash`` method, and a ``__call__``
method. For example:
.. code-block:: python
@@ -1448,27 +1431,27 @@ method. For example:
The constructor of a predicate factory takes two arguments: ``val`` and
``config``. The ``val`` argument will be the argument passed to
-``view_config`` (or ``add_view``). In the example above, it will be the
-string ``File``. The second arg, ``config`` will be the Configurator
-instance at the time of configuration.
+``view_config`` (or ``add_view``). In the example above, it will be the string
+``File``. The second argument, ``config``, will be the Configurator instance
+at the time of configuration.
-The ``text`` method must return a string. It should be useful to describe
-the behavior of the predicate in error messages.
+The ``text`` method must return a string. It should be useful to describe the
+behavior of the predicate in error messages.
-The ``phash`` method must return a string or a sequence of strings. It's
-most often the same as ``text``, as long as ``text`` uniquely describes the
-predicate's name and the value passed to the constructor. If ``text`` is
-more general, or doesn't describe things that way, ``phash`` should return a
-string with the name and the value serialized. The result of ``phash`` is
-not seen in output anywhere, it just informs the uniqueness constraints for
-view configuration.
+The ``phash`` method must return a string or a sequence of strings. It's most
+often the same as ``text``, as long as ``text`` uniquely describes the
+predicate's name and the value passed to the constructor. If ``text`` is more
+general, or doesn't describe things that way, ``phash`` should return a string
+with the name and the value serialized. The result of ``phash`` is not seen in
+output anywhere, it just informs the uniqueness constraints for view
+configuration.
The ``__call__`` method of a predicate factory must accept a resource
-(``context``) and a request, and must return ``True`` or ``False``. It is
-the "meat" of the predicate.
+(``context``) and a request, and must return ``True`` or ``False``. It is the
+"meat" of the predicate.
-You can use the same predicate factory as both a view predicate and as a
-route predicate, but you'll need to call ``add_view_predicate`` and
+You can use the same predicate factory as both a view predicate and as a route
+predicate, but you'll need to call ``add_view_predicate`` and
``add_route_predicate`` separately with the same factory.
.. _subscriber_predicates:
@@ -1476,16 +1459,16 @@ route predicate, but you'll need to call ``add_view_predicate`` and
Subscriber Predicates
~~~~~~~~~~~~~~~~~~~~~
-Subscriber predicates work almost exactly like view and route predicates.
-They narrow the set of circumstances in which a subscriber will be called.
-There are several minor differences between a subscriber predicate and a
-view/route predicate:
+Subscriber predicates work almost exactly like view and route predicates. They
+narrow the set of circumstances in which a subscriber will be called. There are
+several minor differences between a subscriber predicate and a view or route
+predicate:
- There are no default subscriber predicates. You must register one to use
one.
-- The ``__call__`` method of a subscriber predicate accepts a single
- ``event`` object instead of a ``context`` and a ``request``.
+- The ``__call__`` method of a subscriber predicate accepts a single ``event``
+ object instead of a ``context`` and a ``request``.
- Not every subscriber predicate can be used with every event type. Some
subscriber predicates will assume a certain event type.
@@ -1519,8 +1502,8 @@ Once you've created a subscriber predicate, it may registered via
Once a subscriber predicate is registered, you can use it in a call to
:meth:`pyramid.config.Configurator.add_subscriber` or to
-:class:`pyramid.events.subscriber`. Here's an example of using the
-previously registered ``request_path_startswith`` predicate in a call to
+:class:`pyramid.events.subscriber`. Here's an example of using the previously
+registered ``request_path_startswith`` predicate in a call to
:meth:`~pyramid.config.Configurator.add_subscriber`:
.. code-block:: python
@@ -1533,7 +1516,7 @@ previously registered ``request_path_startswith`` predicate in a call to
# and at configuration time
- config.add_subscriber(yosubscriber, NewRequest,
+ config.add_subscriber(yosubscriber, NewRequest,
request_path_startswith='/add_yo')
Here's the same subscriber/predicate/event-type combination used via
@@ -1548,22 +1531,19 @@ Here's the same subscriber/predicate/event-type combination used via
def yosubscriber(event):
event.request.yo = 'YO!'
-In either of the above configurations, the ``yosubscriber`` callable will
-only be called if the request path starts with ``/add_yo``. Otherwise the
-event subscriber will not be called.
+In either of the above configurations, the ``yosubscriber`` callable will only
+be called if the request path starts with ``/add_yo``. Otherwise the event
+subscriber will not be called.
Note that the ``request_path_startswith`` subscriber you defined can be used
with events that have a ``request`` attribute, but not ones that do not. So,
for example, the predicate can be used with subscribers registered for
:class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound`
events, but it cannot be used with subscribers registered for
-:class:`pyramid.events.ApplicationCreated` because the latter type of event
-has no ``request`` attribute. The point being: unlike route and view
-predicates, not every type of subscriber predicate will necessarily be
-applicable for use in every subscriber registration. It is not the
-responsibility of the predicate author to make every predicate make sense for
-every event type; it is the responsibility of the predicate consumer to use
-predicates that make sense for a particular event type registration.
-
-
-
+:class:`pyramid.events.ApplicationCreated` because the latter type of event has
+no ``request`` attribute. The point being, unlike route and view predicates,
+not every type of subscriber predicate will necessarily be applicable for use
+in every subscriber registration. It is not the responsibility of the
+predicate author to make every predicate make sense for every event type; it is
+the responsibility of the predicate consumer to use predicates that make sense
+for a particular event type registration.
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index 1c324d22b..ff26d52ec 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -12,28 +12,26 @@ dispatch. However, to solve a limited set of problems, it's useful to use
.. warning::
Reasoning about the behavior of a "hybrid" URL dispatch + traversal
- application can be challenging. To successfully reason about using
- URL dispatch and traversal together, you need to understand URL
- pattern matching, root factories, and the :term:`traversal`
- algorithm, and the potential interactions between them. Therefore,
- we don't recommend creating an application that relies on hybrid
- behavior unless you must.
+ application can be challenging. To successfully reason about using URL
+ dispatch and traversal together, you need to understand URL pattern
+ matching, root factories, and the :term:`traversal` algorithm, and the
+ potential interactions between them. Therefore, we don't recommend creating
+ an application that relies on hybrid behavior unless you must.
A Review of Non-Hybrid Applications
-----------------------------------
-When used according to the tutorials in its documentation
-:app:`Pyramid` is a "dual-mode" framework: the tutorials explain
-how to create an application in terms of using either :term:`url
-dispatch` *or* :term:`traversal`. This chapter details how you might
-combine these two dispatch mechanisms, but we'll review how they work
-in isolation before trying to combine them.
+When used according to the tutorials in its documentation, :app:`Pyramid` is a
+"dual-mode" framework: the tutorials explain how to create an application in
+terms of using either :term:`URL dispatch` *or* :term:`traversal`. This
+chapter details how you might combine these two dispatch mechanisms, but we'll
+review how they work in isolation before trying to combine them.
URL Dispatch Only
~~~~~~~~~~~~~~~~~
-An application that uses :term:`url dispatch` exclusively to map URLs to code
-will often have statements like this within application startup
+An application that uses :term:`URL dispatch` exclusively to map URLs to code
+will often have statements like this within its application startup
configuration:
.. code-block:: python
@@ -48,11 +46,11 @@ configuration:
config.add_view('myproject.views.bazbuz', route_name='bazbuz')
Each :term:`route` corresponds to one or more view callables. Each view
-callable is associated with a route by passing a ``route_name`` parameter
-that matches its name during a call to
-:meth:`~pyramid.config.Configurator.add_view`. When a route is matched
-during a request, :term:`view lookup` is used to match the request to its
-associated view callable. The presence of calls to
+callable is associated with a route by passing a ``route_name`` parameter that
+matches its name during a call to
+:meth:`~pyramid.config.Configurator.add_view`. When a route is matched during
+a request, :term:`view lookup` is used to match the request to its associated
+view callable. The presence of calls to
:meth:`~pyramid.config.Configurator.add_route` signify that an application is
using URL dispatch.
@@ -72,12 +70,11 @@ declarations that look like this:
When the above configuration is applied to an application, the
``mypackage.views.foobar`` view callable above will be called when the URL
-``/foobar`` is visited. Likewise, the view ``mypackage.views.bazbuz`` will
-be called when the URL ``/bazbuz`` is visited.
+``/foobar`` is visited. Likewise, the view ``mypackage.views.bazbuz`` will be
+called when the URL ``/bazbuz`` is visited.
Typically, an application that uses traversal exclusively won't perform any
-calls to :meth:`pyramid.config.Configurator.add_route` in its startup
-code.
+calls to :meth:`pyramid.config.Configurator.add_route` in its startup code.
.. index::
single: hybrid applications
@@ -85,149 +82,139 @@ code.
Hybrid Applications
-------------------
-Either traversal or url dispatch alone can be used to create a
-:app:`Pyramid` application. However, it is also possible to
-combine the concepts of traversal and url dispatch when building an
-application: the result is a hybrid application. In a hybrid
-application, traversal is performed *after* a particular route has
-matched.
-
-A hybrid application is a lot more like a "pure" traversal-based
-application than it is like a "pure" URL-dispatch based application.
-But unlike in a "pure" traversal-based application, in a hybrid
-application, :term:`traversal` is performed during a request after a
-route has already matched. This means that the URL pattern that
-represents the ``pattern`` argument of a route must match the
-``PATH_INFO`` of a request, and after the route pattern has matched,
-most of the "normal" rules of traversal with respect to :term:`resource
-location` and :term:`view lookup` apply.
+Either traversal or URL dispatch alone can be used to create a :app:`Pyramid`
+application. However, it is also possible to combine the concepts of traversal
+and URL dispatch when building an application, the result of which is a hybrid
+application. In a hybrid application, traversal is performed *after* a
+particular route has matched.
+
+A hybrid application is a lot more like a "pure" traversal-based application
+than it is like a "pure" URL-dispatch based application. But unlike in a "pure"
+traversal-based application, in a hybrid application :term:`traversal` is
+performed during a request after a route has already matched. This means that
+the URL pattern that represents the ``pattern`` argument of a route must match
+the ``PATH_INFO`` of a request, and after the route pattern has matched, most
+of the "normal" rules of traversal with respect to :term:`resource location`
+and :term:`view lookup` apply.
There are only four real differences between a purely traversal-based
application and a hybrid application:
-- In a purely traversal based application, no routes are defined; in a
- hybrid application, at least one route will be defined.
+- In a purely traversal-based application, no routes are defined. In a hybrid
+ application, at least one route will be defined.
-- In a purely traversal based application, the root object used is
- global, implied by the :term:`root factory` provided at startup
- time; in a hybrid application, the :term:`root` object at which
- traversal begins may be varied on a per-route basis.
+- In a purely traversal-based application, the root object used is global,
+ implied by the :term:`root factory` provided at startup time. In a hybrid
+ application, the :term:`root` object at which traversal begins may be varied
+ on a per-route basis.
-- In a purely traversal-based application, the ``PATH_INFO`` of the
- underlying :term:`WSGI` environment is used wholesale as a traversal
- path; in a hybrid application, the traversal path is not the entire
- ``PATH_INFO`` string, but a portion of the URL determined by a
- matching pattern in the matched route configuration's pattern.
+- In a purely traversal-based application, the ``PATH_INFO`` of the underlying
+ :term:`WSGI` environment is used wholesale as a traversal path. In a hybrid
+ application, the traversal path is not the entire ``PATH_INFO`` string, but a
+ portion of the URL determined by a matching pattern in the matched route
+ configuration's pattern.
-- In a purely traversal based application, view configurations which
- do not mention a ``route_name`` argument are considered during
- :term:`view lookup`; in a hybrid application, when a route is
- matched, only view configurations which mention that route's name as
- a ``route_name`` are considered during :term:`view lookup`.
+- In a purely traversal-based application, view configurations which do not
+ mention a ``route_name`` argument are considered during :term:`view lookup`.
+ In a hybrid application, when a route is matched, only view configurations
+ which mention that route's name as a ``route_name`` are considered during
+ :term:`view lookup`.
-More generally, a hybrid application *is* a traversal-based
-application except:
+More generally, a hybrid application *is* a traversal-based application except:
-- the traversal *root* is chosen based on the route configuration of
- the route that matched instead of from the ``root_factory`` supplied
- during application startup configuration.
+- the traversal *root* is chosen based on the route configuration of the route
+ that matched, instead of from the ``root_factory`` supplied during
+ application startup configuration.
-- the traversal *path* is chosen based on the route configuration of
- the route that matched rather than from the ``PATH_INFO`` of a
- request.
+- the traversal *path* is chosen based on the route configuration of the route
+ that matched, rather than from the ``PATH_INFO`` of a request.
-- the set of views that may be chosen during :term:`view lookup` when
- a route matches are limited to those which specifically name a
- ``route_name`` in their configuration that is the same as the
- matched route's ``name``.
+- the set of views that may be chosen during :term:`view lookup` when a route
+ matches are limited to those which specifically name a ``route_name`` in
+ their configuration that is the same as the matched route's ``name``.
-To create a hybrid mode application, use a :term:`route configuration`
-that implies a particular :term:`root factory` and which also includes
-a ``pattern`` argument that contains a special dynamic part: either
-``*traverse`` or ``*subpath``.
+To create a hybrid mode application, use a :term:`route configuration` that
+implies a particular :term:`root factory` and which also includes a ``pattern``
+argument that contains a special dynamic part: either ``*traverse`` or
+``*subpath``.
The Root Object for a Route Match
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A hybrid application implies that traversal is performed during a
-request after a route has matched. Traversal, by definition, must
-always begin at a root object. Therefore it's important to know
-*which* root object will be traversed after a route has matched.
+A hybrid application implies that traversal is performed during a request after
+a route has matched. Traversal, by definition, must always begin at a root
+object. Therefore it's important to know *which* root object will be traversed
+after a route has matched.
-Figuring out which :term:`root` object results from a particular route
-match is straightforward. When a route is matched:
+Figuring out which :term:`root` object results from a particular route match is
+straightforward. When a route is matched:
-- If the route's configuration has a ``factory`` argument which
- points to a :term:`root factory` callable, that callable will be
- called to generate a :term:`root` object.
+- If the route's configuration has a ``factory`` argument which points to a
+ :term:`root factory` callable, that callable will be called to generate a
+ :term:`root` object.
-- If the route's configuration does not have a ``factory``
- argument, the *global* :term:`root factory` will be called to
- generate a :term:`root` object. The global root factory is the
- callable implied by the ``root_factory`` argument passed to the
- :class:`~pyramid.config.Configurator` at application
- startup time.
+- If the route's configuration does not have a ``factory`` argument, the
+ *global* :term:`root factory` will be called to generate a :term:`root`
+ object. The global root factory is the callable implied by the
+ ``root_factory`` argument passed to the :class:`~pyramid.config.Configurator`
+ at application startup time.
- If a ``root_factory`` argument is not provided to the
- :class:`~pyramid.config.Configurator` at startup time, a
- *default* root factory is used. The default root factory is used to
- generate a root object.
+ :class:`~pyramid.config.Configurator` at startup time, a *default* root
+ factory is used. The default root factory is used to generate a root object.
.. note::
Root factories related to a route were explained previously within
- :ref:`route_factories`. Both the global root factory and default
- root factory were explained previously within
- :ref:`the_resource_tree`.
+ :ref:`route_factories`. Both the global root factory and default root
+ factory were explained previously within :ref:`the_resource_tree`.
.. index::
pair: hybrid applications; *traverse route pattern
.. _using_traverse_in_a_route_pattern:
-Using ``*traverse`` In a Route Pattern
+Using ``*traverse`` in a Route Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A hybrid application most often implies the inclusion of a route
-configuration that contains the special token ``*traverse`` at the end
-of a route's pattern:
+A hybrid application most often implies the inclusion of a route configuration
+that contains the special token ``*traverse`` at the end of a route's pattern:
.. code-block:: python
:linenos:
config.add_route('home', '{foo}/{bar}/*traverse')
-A ``*traverse`` token at the end of the pattern in a route's
-configuration implies a "remainder" *capture* value. When it is used,
-it will match the remainder of the path segments of the URL. This
-remainder becomes the path used to perform traversal.
+A ``*traverse`` token at the end of the pattern in a route's configuration
+implies a "remainder" *capture* value. When it is used, it will match the
+remainder of the path segments of the URL. This remainder becomes the path
+used to perform traversal.
.. note::
- The ``*remainder`` route pattern syntax is explained in more
- detail within :ref:`route_pattern_syntax`.
+ The ``*remainder`` route pattern syntax is explained in more detail within
+ :ref:`route_pattern_syntax`.
A hybrid mode application relies more heavily on :term:`traversal` to do
:term:`resource location` and :term:`view lookup` than most examples indicate
within :ref:`urldispatch_chapter`.
-Because the pattern of the above route ends with ``*traverse``, when this
-route configuration is matched during a request, :app:`Pyramid` will attempt
-to use :term:`traversal` against the :term:`root` object implied by the
-:term:`root factory` that is implied by the route's configuration. Since no
+Because the pattern of the above route ends with ``*traverse``, when this route
+configuration is matched during a request, :app:`Pyramid` will attempt to use
+:term:`traversal` against the :term:`root` object implied by the :term:`root
+factory` that is implied by the route's configuration. Since no
``root_factory`` argument is explicitly specified for this route, this will
-either be the *global* root factory for the application, or the *default*
-root factory. Once :term:`traversal` has found a :term:`context` resource,
+either be the *global* root factory for the application, or the *default* root
+factory. Once :term:`traversal` has found a :term:`context` resource,
:term:`view lookup` will be invoked in almost exactly the same way it would
have been invoked in a "pure" traversal-based application.
-Let's assume there is no *global* :term:`root factory` configured in
-this application. The *default* :term:`root factory` cannot be traversed:
-it has no useful ``__getitem__`` method. So we'll need to associate
-this route configuration with a custom root factory in order to
-create a useful hybrid application. To that end, let's imagine that
-we've created a root factory that looks like so in a module named
-``routes.py``:
+Let's assume there is no *global* :term:`root factory` configured in this
+application. The *default* :term:`root factory` cannot be traversed; it has no
+useful ``__getitem__`` method. So we'll need to associate this route
+configuration with a custom root factory in order to create a useful hybrid
+application. To that end, let's imagine that we've created a root factory that
+looks like so in a module named ``routes.py``:
.. code-block:: python
:linenos:
@@ -246,7 +233,7 @@ we've created a root factory that looks like so in a module named
def root_factory(request):
return root
-Above, we've defined a (bogus) resource tree that can be traversed, and a
+Above we've defined a (bogus) resource tree that can be traversed, and a
``root_factory`` function that can be used as part of a particular route
configuration statement:
@@ -256,8 +243,8 @@ configuration statement:
config.add_route('home', '{foo}/{bar}/*traverse',
factory='mypackage.routes.root_factory')
-The ``factory`` above points at the function we've defined. It will return
-an instance of the ``Resource`` class as a root object whenever this route is
+The ``factory`` above points at the function we've defined. It will return an
+instance of the ``Resource`` class as a root object whenever this route is
matched. Instances of the ``Resource`` class can be used for tree traversal
because they have a ``__getitem__`` method that does something nominally
useful. Since traversal uses ``__getitem__`` to walk the resources of a
@@ -266,39 +253,37 @@ statement is a reasonable thing to do.
.. note::
- We could have also used our ``root_factory`` function as the
- ``root_factory`` argument of the
- :class:`~pyramid.config.Configurator` constructor, instead
- of associating it with a particular route inside the route's
- configuration. Every hybrid route configuration that is matched but
- which does *not* name a ``factory`` attribute will use the use
- global ``root_factory`` function to generate a root object.
+ We could have also used our ``root_factory`` function as the ``root_factory``
+ argument of the :class:`~pyramid.config.Configurator` constructor, instead of
+ associating it with a particular route inside the route's configuration.
+ Every hybrid route configuration that is matched, but which does *not* name a
+ ``factory`` attribute, will use the global ``root_factory`` function to
+ generate a root object.
-When the route configuration named ``home`` above is matched during a
-request, the matchdict generated will be based on its pattern:
+When the route configuration named ``home`` above is matched during a request,
+the matchdict generated will be based on its pattern:
``{foo}/{bar}/*traverse``. The "capture value" implied by the ``*traverse``
element in the pattern will be used to traverse the resource tree in order to
find a context resource, starting from the root object returned from the root
factory. In the above example, the :term:`root` object found will be the
instance named ``root`` in ``routes.py``.
-If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse``,
-is ``http://example.com/one/two/a/b/c``, the traversal path used
-against the root object will be ``a/b/c``. As a result,
-:app:`Pyramid` will attempt to traverse through the edges ``'a'``,
-``'b'``, and ``'c'``, beginning at the root object.
+If the URL that matched a route with the pattern ``{foo}/{bar}/*traverse`` is
+``http://example.com/one/two/a/b/c``, the traversal path used against the root
+object will be ``a/b/c``. As a result, :app:`Pyramid` will attempt to traverse
+through the edges ``'a'``, ``'b'``, and ``'c'``, beginning at the root object.
-In our above example, this particular set of traversal steps will mean that
-the :term:`context` resource of the view would be the ``Resource`` object
-we've named ``'c'`` in our bogus resource tree and the :term:`view name`
-resulting from traversal will be the empty string; if you need a refresher
-about why this outcome is presumed, see :ref:`traversal_algorithm`.
+In our above example, this particular set of traversal steps will mean that the
+:term:`context` resource of the view would be the ``Resource`` object we've
+named ``'c'`` in our bogus resource tree, and the :term:`view name` resulting
+from traversal will be the empty string. If you need a refresher about why
+this outcome is presumed, see :ref:`traversal_algorithm`.
-At this point, a suitable view callable will be found and invoked
-using :term:`view lookup` as described in :ref:`view_configuration`,
-but with a caveat: in order for view lookup to work, we need to define
-a view configuration that will match when :term:`view lookup` is
-invoked after a route matches:
+At this point, a suitable view callable will be found and invoked using
+:term:`view lookup` as described in :ref:`view_configuration`, but with a
+caveat: in order for view lookup to work, we need to define a view
+configuration that will match when :term:`view lookup` is invoked after a route
+matches:
.. code-block:: python
:linenos:
@@ -307,28 +292,28 @@ invoked after a route matches:
factory='mypackage.routes.root_factory')
config.add_view('mypackage.views.myview', route_name='home')
-Note that the above call to
-:meth:`~pyramid.config.Configurator.add_view` includes a ``route_name``
-argument. View configurations that include a ``route_name`` argument are
-meant to associate a particular view declaration with a route, using the
-route's name, in order to indicate that the view should *only be invoked when
-the route matches*.
+Note that the above call to :meth:`~pyramid.config.Configurator.add_view`
+includes a ``route_name`` argument. View configurations that include a
+``route_name`` argument are meant to associate a particular view declaration
+with a route, using the route's name, in order to indicate that the view should
+*only be invoked when the route matches*.
Calls to :meth:`~pyramid.config.Configurator.add_view` may pass a
``route_name`` attribute, which refers to the value of an existing route's
-``name`` argument. In the above example, the route name is ``home``,
-referring to the name of the route defined above it.
+``name`` argument. In the above example, the route name is ``home``, referring
+to the name of the route defined above it.
-The above ``mypackage.views.myview`` view callable will be invoked when:
+The above ``mypackage.views.myview`` view callable will be invoked when the
+following conditions are met:
-- the route named "home" is matched
+- The route named "home" is matched.
-- the :term:`view name` resulting from traversal is the empty string.
+- The :term:`view name` resulting from traversal is the empty string.
-- the :term:`context` resource is any object.
+- The :term:`context` resource is any object.
-It is also possible to declare alternate views that may be invoked
-when a hybrid route is matched:
+It is also possible to declare alternative views that may be invoked when a
+hybrid route is matched:
.. code-block:: python
:linenos:
@@ -340,37 +325,37 @@ when a hybrid route is matched:
name='another')
The ``add_view`` call for ``mypackage.views.another_view`` above names a
-different view and, more importantly, a different :term:`view name`. The
-above ``mypackage.views.another_view`` view will be invoked when:
+different view and, more importantly, a different :term:`view name`. The above
+``mypackage.views.another_view`` view will be invoked when the following
+conditions are met:
-- the route named "home" is matched
+- The route named "home" is matched.
-- the :term:`view name` resulting from traversal is ``another``.
+- The :term:`view name` resulting from traversal is ``another``.
-- the :term:`context` resource is any object.
+- The :term:`context` resource is any object.
For instance, if the URL ``http://example.com/one/two/a/another`` is provided
to an application that uses the previously mentioned resource tree, the
-``mypackage.views.another`` view callable will be called instead of the
-``mypackage.views.myview`` view callable because the :term:`view name` will
-be ``another`` instead of the empty string.
+``mypackage.views.another_view`` view callable will be called instead of the
+``mypackage.views.myview`` view callable because the :term:`view name` will be
+``another`` instead of the empty string.
More complicated matching can be composed. All arguments to *route*
-configuration statements and *view* configuration statements are
-supported in hybrid applications (such as :term:`predicate`
-arguments).
+configuration statements and *view* configuration statements are supported in
+hybrid applications (such as :term:`predicate` arguments).
-Using the ``traverse`` Argument In a Route Definition
+Using the ``traverse`` Argument in a Route Definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Rather than using the ``*traverse`` remainder marker in a pattern, you
-can use the ``traverse`` argument to the
-:meth:`~pyramid.config.Configurator.add_route` method.
+Rather than using the ``*traverse`` remainder marker in a pattern, you can use
+the ``traverse`` argument to the :meth:`~pyramid.config.Configurator.add_route`
+method.
-When you use the ``*traverse`` remainder marker, the traversal path is
-limited to being the remainder segments of a request URL when a route
-matches. However, when you use the ``traverse`` argument or
-attribute, you have more control over how to compose a traversal path.
+When you use the ``*traverse`` remainder marker, the traversal path is limited
+to being the remainder segments of a request URL when a route matches.
+However, when you use the ``traverse`` argument or attribute, you have more
+control over how to compose a traversal path.
Here's a use of the ``traverse`` pattern in a call to
:meth:`~pyramid.config.Configurator.add_route`:
@@ -381,30 +366,27 @@ Here's a use of the ``traverse`` pattern in a call to
config.add_route('abc', '/articles/{article}/edit',
traverse='/{article}')
-The syntax of the ``traverse`` argument is the same as it is for
-``pattern``.
+The syntax of the ``traverse`` argument is the same as it is for ``pattern``.
-If, as above, the ``pattern`` provided is ``/articles/{article}/edit``,
-and the ``traverse`` argument provided is ``/{article}``, when a
-request comes in that causes the route to match in such a way that the
-``article`` match value is ``1`` (when the request URI is
-``/articles/1/edit``), the traversal path will be generated as ``/1``.
-This means that the root object's ``__getitem__`` will be called with
-the name ``1`` during the traversal phase. If the ``1`` object
-exists, it will become the :term:`context` of the request.
-The :ref:`traversal_chapter` chapter has more information about traversal.
+If, as above, the ``pattern`` provided is ``/articles/{article}/edit``, and the
+``traverse`` argument provided is ``/{article}``, when a request comes in that
+causes the route to match in such a way that the ``article`` match value is
+``1`` (when the request URI is ``/articles/1/edit``), the traversal path will
+be generated as ``/1``. This means that the root object's ``__getitem__`` will
+be called with the name ``1`` during the traversal phase. If the ``1`` object
+exists, it will become the :term:`context` of the request. The
+:ref:`traversal_chapter` chapter has more information about traversal.
-If the traversal path contains segment marker names which are not
-present in the pattern argument, a runtime error will occur. The
-``traverse`` pattern should not contain segment markers that do not
-exist in the ``path``.
+If the traversal path contains segment marker names which are not present in
+the pattern argument, a runtime error will occur. The ``traverse`` pattern
+should not contain segment markers that do not exist in the ``path``.
-Note that the ``traverse`` argument is ignored when attached to a
-route that has a ``*traverse`` remainder marker in its pattern.
+Note that the ``traverse`` argument is ignored when attached to a route that
+has a ``*traverse`` remainder marker in its pattern.
-Traversal will begin at the root object implied by this route (either
-the global root, or the object returned by the ``factory`` associated
-with this route).
+Traversal will begin at the root object implied by this route (either the
+global root, or the object returned by the ``factory`` associated with this
+route).
.. index::
pair: hybrid applications; global views
@@ -412,14 +394,13 @@ with this route).
Making Global Views Match
+++++++++++++++++++++++++
-By default, only view configurations that mention a ``route_name``
-will be found during view lookup when a route that has a ``*traverse``
-in its pattern matches. You can allow views without a ``route_name``
-attribute to match a route by adding the ``use_global_views`` flag to
-the route definition. For example, the ``myproject.views.bazbuz``
-view below will be found if the route named ``abc`` below is matched
-and the ``PATH_INFO`` is ``/abc/bazbuz``, even though the view
-configuration statement does not have the ``route_name="abc"``
+By default, only view configurations that mention a ``route_name`` will be
+found during view lookup when a route that has a ``*traverse`` in its pattern
+matches. You can allow views without a ``route_name`` attribute to match a
+route by adding the ``use_global_views`` flag to the route definition. For
+example, the ``myproject.views.bazbuz`` view below will be found if the route
+named ``abc`` below is matched and the ``PATH_INFO`` is ``/abc/bazbuz``, even
+though the view configuration statement does not have the ``route_name="abc"``
attribute.
.. code-block:: python
@@ -445,10 +426,10 @@ traversal. For instance, the :func:`pyramid.wsgi.wsgiapp2` decorator and the
from the request's subpath when its ``use_subpath`` argument is ``True``, so
it's useful to be able to influence this value.
-When ``*subpath`` exists in a pattern, no path is actually traversed,
-but the traversal algorithm will return a :term:`subpath` list implied
-by the capture value of ``*subpath``. You'll see this pattern most
-commonly in route declarations that look like this:
+When ``*subpath`` exists in a pattern, no path is actually traversed, but the
+traversal algorithm will return a :term:`subpath` list implied by the capture
+value of ``*subpath``. You'll see this pattern most commonly in route
+declarations that look like this:
.. code-block:: python
:linenos:
@@ -460,98 +441,13 @@ commonly in route declarations that look like this:
config.add_route('static', '/static/*subpath')
config.add_view(www, route_name='static')
-``mypackage.views.www`` is an instance of
-:class:`pyramid.static.static_view`. This effectively tells the static
-helper to traverse everything in the subpath as a filename.
-
-.. index::
- pair: hybrid applications; corner cases
-
-Corner Cases
-------------
-
-A number of corner case "gotchas" exist when using a hybrid
-application. We'll detail them here.
-
-Registering a Default View for a Route That Has a ``view`` Attribute
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. warning:: As of :app:`Pyramid` 1.1 this section is slated to be removed in
- a later documentation release because the ability to add views
- directly to the :term:`route configuration` by passing a ``view`` argument
- to ``add_route`` has been deprecated.
-
-It is an error to provide *both* a ``view`` argument to a :term:`route
-configuration` *and* a :term:`view configuration` which names a
-``route_name`` that has no ``name`` value or the empty ``name`` value. For
-example, this pair of declarations will generate a conflict error at startup
-time.
-
-.. code-block:: python
- :linenos:
-
- config.add_route('home', '{foo}/{bar}/*traverse',
- view='myproject.views.home')
- config.add_view('myproject.views.another', route_name='home')
-
-This is because the ``view`` argument to the
-:meth:`~pyramid.config.Configurator.add_route` above is an *implicit*
-default view when that route matches. ``add_route`` calls don't *need* to
-supply a view attribute. For example, this ``add_route`` call:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('home', '{foo}/{bar}/*traverse',
- view='myproject.views.home')
+``mypackage.views.www`` is an instance of :class:`pyramid.static.static_view`.
+This effectively tells the static helper to traverse everything in the subpath
+as a filename.
-Can also be spelled like so:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('home', '{foo}/{bar}/*traverse')
- config.add_view('myproject.views.home', route_name='home')
-
-The two spellings are logically equivalent. In fact, the former is just a
-syntactical shortcut for the latter.
-
-Binding Extra Views Against a Route Configuration that Doesn't Have a ``*traverse`` Element In Its Pattern
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's another corner case that just makes no sense:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('abc', '/abc', view='myproject.views.abc')
- config.add_view('myproject.views.bazbuz', name='bazbuz',
- route_name='abc')
-
-The above view declaration is useless, because it will never be matched when
-the route it references has matched. Only the view associated with the route
-itself (``myproject.views.abc``) will ever be invoked when the route matches,
-because the default view is always invoked when a route matches and when no
-post-match traversal is performed.
-
-To make the above view declaration useful, the special ``*traverse``
-token must end the route's pattern. For example:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('abc', '/abc/*traverse', view='myproject.views.abc')
- config.add_view('myproject.views.bazbuz', name='bazbuz',
- route_name='abc')
-
-With the above configuration, the ``myproject.views.bazbuz`` view will
-be invoked when the request URI is ``/abc/bazbuz``, assuming there is
-no object contained by the root object with the key ``bazbuz``. A
-different request URI, such as ``/abc/foo/bar``, would invoke the
-default ``myproject.views.abc`` view.
.. index::
- pair: hybrid urls; generating
+ pair: hybrid URLs; generating
.. _generating_hybrid_urls:
@@ -560,16 +456,16 @@ Generating Hybrid URLs
.. versionadded:: 1.5
-The :meth:`pyramid.request.Request.resource_url` method and the
-:meth:`pyramid.request.Request.resource_path` method both accept optional
+The :meth:`pyramid.request.Request.resource_url` method and the
+:meth:`pyramid.request.Request.resource_path` method both accept optional
keyword arguments that make it easier to generate route-prefixed URLs that
-contain paths to traversal resources:``route_name``, ``route_kw``, and
+contain paths to traversal resources: ``route_name``, ``route_kw``, and
``route_remainder_name``.
Any route that has a pattern that contains a ``*remainder`` pattern (any
-stararg remainder pattern, such as ``*traverse`` or ``*subpath`` or ``*fred``)
-can be used as the target name for ``request.resource_url(..., route_name=)``
-and ``request.resource_path(..., route_name=)``.
+stararg remainder pattern, such as ``*traverse``, ``*subpath``, or ``*fred``)
+can be used as the target name for ``request.resource_url(..., route_name=)``
+and ``request.resource_path(..., route_name=)``.
For example, let's imagine you have a route defined in your Pyramid application
like so:
@@ -578,7 +474,7 @@ like so:
config.add_route('mysection', '/mysection*traverse')
-If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
+If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
use the following incantation, assuming that the variable ``a`` below points to
a resource that is a child of the root with a ``__name__`` of ``a``:
@@ -592,14 +488,14 @@ You can generate only the path portion ``/mysection/a/`` assuming the same:
request.resource_path(a, route_name='mysection')
-The path is virtual host aware, so if the ``X-Vhm-Root`` environ variable is
-present in the request, and it's set to ``/a``, the above call to
-``request.resource_url`` would generate ``http://example.com/mysection/``
-and the above call to ``request.resource_path`` would generate ``/mysection/``.
-See :ref:`virtual_root_support` for more information.
+The path is virtual host aware, so if the ``X-Vhm-Root`` environment variable
+is present in the request, and it's set to ``/a``, the above call to
+``request.resource_url`` would generate ``http://example.com/mysection/``, and
+the above call to ``request.resource_path`` would generate ``/mysection/``. See
+:ref:`virtual_root_support` for more information.
If the route you're trying to use needs simple dynamic part values to be filled
-in to succesfully generate the URL, you can pass these as the ``route_kw``
+in to succesfully generate the URL, you can pass these as the ``route_kw``
argument to ``resource_url`` and ``resource_path``. For example, assuming that
the route definition is like so:
@@ -613,15 +509,15 @@ You can pass ``route_kw`` in to fill in ``{id}`` above:
request.resource_url(a, route_name='mysection', route_kw={'id':'1'})
-If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will
-be ignored.
+If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will be
+ignored.
-By default this feature works by calling ``route_url`` under the hood,
-and passing the value of the resource path to that function as ``traverse``.
-If your route has a different ``*stararg`` remainder name (such as
-``*subpath``), you can tell ``resource_url`` or ``resource_path`` to use that
-instead of ``traverse`` by passing ``route_remainder_name``. For example,
-if you have the following route:
+By default this feature works by calling ``route_url`` under the hood, and
+passing the value of the resource path to that function as ``traverse``. If
+your route has a different ``*stararg`` remainder name (such as ``*subpath``),
+you can tell ``resource_url`` or ``resource_path`` to use that instead of
+``traverse`` by passing ``route_remainder_name``. For example, if you have the
+following route:
.. code-block:: python
@@ -631,10 +527,10 @@ You can fill in the ``*subpath`` value using ``resource_url`` by doing:
.. code-block:: python
- request.resource_path(a, route_name='mysection',
+ request.resource_path(a, route_name='mysection',
route_remainder_name='subpath')
-If you pass ``route_remainder_name`` but do not pass ``route_name``,
+If you pass ``route_remainder_name`` but do not pass ``route_name``,
``route_remainder_name`` will be ignored.
If you try to use ``resource_path`` or ``resource_url`` when the ``route_name``
@@ -642,12 +538,11 @@ argument points at a route that does not have a remainder stararg, an error
will not be raised, but the generated URL will not contain any remainder
information either.
-All other values that are normally passable to ``resource_path`` and
-``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and
+All other values that are normally passable to ``resource_path`` and
+``resource_url`` (such as ``query``, ``anchor``, ``host``, ``port``, and
positional elements) work as you might expect in this configuration.
Note that this feature is incompatible with the ``__resource_url__`` feature
(see :ref:`overriding_resource_url_generation`) implemented on resource
objects. Any ``__resource_url__`` supplied by your resource will be ignored
when you pass ``route_name``.
-
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
index 8caba522c..98315ac9f 100644
--- a/docs/narr/introspector.rst
+++ b/docs/narr/introspector.rst
@@ -20,8 +20,7 @@ configuration settings.
Using the Introspector
----------------------
-Here's an example of using Pyramid's introspector from within a view
-callable:
+Here's an example of using Pyramid's introspector from within a view callable:
.. code-block:: python
:linenos:
@@ -36,10 +35,10 @@ callable:
route_intr = introspector.get('routes', route_name)
return Response(str(route_intr['pattern']))
-This view will return a response that contains the "pattern" argument
-provided to the ``add_route`` method of the route which matched when the view
-was called. It uses the :meth:`pyramid.interfaces.IIntrospector.get` method
-to return an introspectable in the category ``routes`` with a
+This view will return a response that contains the "pattern" argument provided
+to the ``add_route`` method of the route which matched when the view was
+called. It uses the :meth:`pyramid.interfaces.IIntrospector.get` method to
+return an introspectable in the category ``routes`` with a
:term:`discriminator` equal to the matched route name. It then uses the
returned introspectable to obtain a "pattern" value.
@@ -56,9 +55,9 @@ can be used to query for introspectables.
Introspectable Objects
----------------------
-Introspectable objects are returned from query methods of an introspector.
-Each introspectable object implements the attributes and methods
-documented at :class:`pyramid.interfaces.IIntrospectable`.
+Introspectable objects are returned from query methods of an introspector. Each
+introspectable object implements the attributes and methods documented at
+:class:`pyramid.interfaces.IIntrospectable`.
The important attributes shared by all introspectables are the following:
@@ -74,12 +73,12 @@ The important attributes shared by all introspectables are the following:
``discriminator``
- A hashable object representing the unique value of this introspectable
- within its category.
+ A hashable object representing the unique value of this introspectable within
+ its category.
``discriminator_hash``
- The integer hash of the discriminator (useful for using in HTML links).
+ The integer hash of the discriminator (useful in HTML links).
``type_name``
@@ -90,8 +89,8 @@ The important attributes shared by all introspectables are the following:
``action_info``
- An object describing the directive call site which caused this
- introspectable to be registered; contains attributes described in
+ An object describing the directive call site which caused this introspectable
+ to be registered. It contains attributes described in
:class:`pyramid.interfaces.IActionInfo`.
Besides having the attributes described above, an introspectable is a
@@ -116,7 +115,7 @@ introspectables in categories not described here.
Each introspectable in the ``subscribers`` category represents a call to
:meth:`pyramid.config.Configurator.add_subscriber` (or the decorator
- equivalent); each will have the following data.
+ equivalent). Each will have the following data.
``subscriber``
@@ -137,7 +136,7 @@ introspectables in categories not described here.
``predicates``
The predicate objects created as the result of passing predicate arguments
- to ``add_subscriber``
+ to ``add_subscriber``.
``derived_predicates``
@@ -149,7 +148,7 @@ introspectables in categories not described here.
Each introspectable in the ``response adapters`` category represents a call
to :meth:`pyramid.config.Configurator.add_response_adapter` (or a decorator
- equivalent); each will have the following data.
+ equivalent). Each will have the following data.
``adapter``
@@ -158,15 +157,14 @@ introspectables in categories not described here.
``type``
- The resolved ``type_or_iface`` argument passed to
- ``add_response_adapter``.
+ The resolved ``type_or_iface`` argument passed to ``add_response_adapter``.
``root factories``
Each introspectable in the ``root factories`` category represents a call to
:meth:`pyramid.config.Configurator.set_root_factory` (or the Configurator
constructor equivalent) *or* a ``factory`` argument passed to
- :meth:`pyramid.config.Configurator.add_route`; each will have the following
+ :meth:`pyramid.config.Configurator.add_route`. Each will have the following
data.
``factory``
@@ -184,7 +182,7 @@ introspectables in categories not described here.
Only one introspectable will exist in the ``session factory`` category. It
represents a call to :meth:`pyramid.config.Configurator.set_session_factory`
- (or the Configurator constructor equivalent); it will have the following
+ (or the Configurator constructor equivalent). It will have the following
data.
``factory``
@@ -196,7 +194,7 @@ introspectables in categories not described here.
Only one introspectable will exist in the ``request factory`` category. It
represents a call to :meth:`pyramid.config.Configurator.set_request_factory`
- (or the Configurator constructor equivalent); it will have the following
+ (or the Configurator constructor equivalent). It will have the following
data.
``factory``
@@ -206,10 +204,10 @@ introspectables in categories not described here.
``locale negotiator``
- Only one introspectable will exist in the ``locale negotiator`` category.
- It represents a call to
+ Only one introspectable will exist in the ``locale negotiator`` category. It
+ represents a call to
:meth:`pyramid.config.Configurator.set_locale_negotiator` (or the
- Configurator constructor equivalent); it will have the following data.
+ Configurator constructor equivalent). It will have the following data.
``negotiator``
@@ -218,9 +216,9 @@ introspectables in categories not described here.
``renderer factories``
- Each introspectable in the ``renderer factories`` category represents a
- call to :meth:`pyramid.config.Configurator.add_renderer` (or the
- Configurator constructor equivalent); each will have the following data.
+ Each introspectable in the ``renderer factories`` category represents a call
+ to :meth:`pyramid.config.Configurator.add_renderer` (or the Configurator
+ constructor equivalent). Each will have the following data.
``name``
@@ -229,13 +227,12 @@ introspectables in categories not described here.
``factory``
- The factory object (the resolved ``factory`` argument to
- ``add_renderer``).
+ The factory object (the resolved ``factory`` argument to ``add_renderer``).
``routes``
Each introspectable in the ``routes`` category represents a call to
- :meth:`pyramid.config.Configurator.add_route`; each will have the following
+ :meth:`pyramid.config.Configurator.add_route`. Each will have the following
data.
``name``
@@ -310,7 +307,7 @@ introspectables in categories not described here.
There will be one and only one introspectable in the ``authentication
policy`` category. It represents a call to the
:meth:`pyramid.config.Configurator.set_authentication_policy` method (or
- its Configurator constructor equivalent); it will have the following data.
+ its Configurator constructor equivalent). It will have the following data.
``policy``
@@ -319,10 +316,10 @@ introspectables in categories not described here.
``authorization policy``
- There will be one and only one introspectable in the ``authorization
- policy`` category. It represents a call to the
+ There will be one and only one introspectable in the ``authorization policy``
+ category. It represents a call to the
:meth:`pyramid.config.Configurator.set_authorization_policy` method (or its
- Configurator constructor equivalent); it will have the following data.
+ Configurator constructor equivalent). It will have the following data.
``policy``
@@ -334,7 +331,7 @@ introspectables in categories not described here.
There will be one and only one introspectable in the ``default permission``
category. It represents a call to the
:meth:`pyramid.config.Configurator.set_default_permission` method (or its
- Configurator constructor equivalent); it will have the following data.
+ Configurator constructor equivalent). It will have the following data.
``value``
@@ -343,7 +340,7 @@ introspectables in categories not described here.
``views``
Each introspectable in the ``views`` category represents a call to
- :meth:`pyramid.config.Configurator.add_view`; each will have the following
+ :meth:`pyramid.config.Configurator.add_view`. Each will have the following
data.
``name``
@@ -423,8 +420,8 @@ introspectables in categories not described here.
Each introspectable in the ``permissions`` category represents a call to
:meth:`pyramid.config.Configurator.add_view` that has an explicit
- ``permission`` argument to *or* a call to
- :meth:`pyramid.config.Configurator.set_default_permission`; each will have
+ ``permission`` argument *or* a call to
+ :meth:`pyramid.config.Configurator.set_default_permission`. Each will have
the following data.
``value``
@@ -435,7 +432,7 @@ introspectables in categories not described here.
Each introspectable in the ``templates`` category represents a call to
:meth:`pyramid.config.Configurator.add_view` that has a ``renderer``
- argument which points to a template; each will have the following data.
+ argument which points to a template. Each will have the following data.
``name``
@@ -447,15 +444,15 @@ introspectables in categories not described here.
``renderer``
- The :class:`pyramid.interfaces.IRendererInfo` object which represents
- this template's renderer.
+ The :class:`pyramid.interfaces.IRendererInfo` object which represents this
+ template's renderer.
``view mappers``
Each introspectable in the ``view mappers`` category represents a call to
- :meth:`pyramid.config.Configurator.add_view` that has an explicit
- ``mapper`` argument to *or* a call to
- :meth:`pyramid.config.Configurator.set_view_mapper`; each will have
+ :meth:`pyramid.config.Configurator.add_view` that has an explicit ``mapper``
+ argument *or* a call to
+ :meth:`pyramid.config.Configurator.set_view_mapper`. Each will have
the following data.
``mapper``
@@ -465,14 +462,13 @@ introspectables in categories not described here.
``asset overrides``
- Each introspectable in the ``asset overrides`` category represents a call
- to :meth:`pyramid.config.Configurator.override_asset`; each will have the
+ Each introspectable in the ``asset overrides`` category represents a call to
+ :meth:`pyramid.config.Configurator.override_asset`. Each will have the
following data.
``to_override``
- The ``to_override`` argument (an asset spec) passed to
- ``override_asset``.
+ The ``to_override`` argument (an asset spec) passed to ``override_asset``.
``override_with``
@@ -481,10 +477,10 @@ introspectables in categories not described here.
``translation directories``
- Each introspectable in the ``translation directories`` category represents
- an individual element in a ``specs`` argument passed to
- :meth:`pyramid.config.Configurator.add_translation_dirs`; each will have
- the following data.
+ Each introspectable in the ``translation directories`` category represents an
+ individual element in a ``specs`` argument passed to
+ :meth:`pyramid.config.Configurator.add_translation_dirs`. Each will have the
+ following data.
``directory``
@@ -497,13 +493,13 @@ introspectables in categories not described here.
``tweens``
Each introspectable in the ``tweens`` category represents a call to
- :meth:`pyramid.config.Configurator.add_tween`; each will have the following
+ :meth:`pyramid.config.Configurator.add_tween`. Each will have the following
data.
``name``
- The dotted name to the tween factory as a string (passed as
- the ``tween_factory`` argument to ``add_tween``).
+ The dotted name to the tween factory as a string (passed as the
+ ``tween_factory`` argument to ``add_tween``).
``factory``
@@ -524,7 +520,7 @@ introspectables in categories not described here.
``static views``
Each introspectable in the ``static views`` category represents a call to
- :meth:`pyramid.config.Configurator.add_static_view`; each will have the
+ :meth:`pyramid.config.Configurator.add_static_view`. Each will have the
following data.
``name``
@@ -539,13 +535,13 @@ introspectables in categories not described here.
``traversers``
Each introspectable in the ``traversers`` category represents a call to
- :meth:`pyramid.config.Configurator.add_traverser`; each will have the
+ :meth:`pyramid.config.Configurator.add_traverser`. Each will have the
following data.
``iface``
The (resolved) interface or class object that represents the return value
- of a root factory that this traverser will be used for.
+ of a root factory for which this traverser will be used.
``adapter``
@@ -554,7 +550,7 @@ introspectables in categories not described here.
``resource url adapters``
Each introspectable in the ``resource url adapters`` category represents a
- call to :meth:`pyramid.config.Configurator.add_resource_url_adapter`; each
+ call to :meth:`pyramid.config.Configurator.add_resource_url_adapter`. Each
will have the following data.
``adapter``
@@ -564,19 +560,20 @@ introspectables in categories not described here.
``resource_iface``
The (resolved) interface or class object that represents the resource
- interface that this url adapter is registered for.
+ interface for which this URL adapter is registered.
``request_iface``
The (resolved) interface or class object that represents the request
- interface that this url adapter is registered for.
+ interface for which this URL adapter is registered.
Introspection in the Toolbar
----------------------------
The Pyramid debug toolbar (part of the ``pyramid_debugtoolbar`` package)
provides a canned view of all registered introspectables and their
-relationships. It looks something like this:
+relationships. It is currently under the "Global" tab in the main navigation,
+and it looks something like this:
.. image:: tb_introspector.png
diff --git a/docs/narr/muchadoabouttraversal.rst b/docs/narr/muchadoabouttraversal.rst
index 483b1bb16..3e00a295a 100644
--- a/docs/narr/muchadoabouttraversal.rst
+++ b/docs/narr/muchadoabouttraversal.rst
@@ -4,44 +4,44 @@
Much Ado About Traversal
========================
-(Or, why you should care about it)
+(Or, why you should care about it.)
.. note::
- This chapter was adapted, with permission, from a blog post by `Rob
- Miller <http://blog.nonsequitarian.org/>`_, originally published at
- http://blog.nonsequitarian.org/2010/much-ado-about-traversal/ .
+ This chapter was adapted, with permission, from a blog post by `Rob Miller
+ <http://blog.nonsequitarian.org/>`_, originally published at
+ http://blog.nonsequitarian.org/2010/much-ado-about-traversal/.
-Traversal is an alternative to :term:`URL dispatch` which allows
-:app:`Pyramid` applications to map URLs to code.
+Traversal is an alternative to :term:`URL dispatch` which allows :app:`Pyramid`
+applications to map URLs to code.
.. note::
Ex-Zope users who are already familiar with traversal and view lookup
conceptually may want to skip directly to the :ref:`traversal_chapter`
- chapter, which discusses technical details. This chapter is mostly aimed
- at people who have previous :term:`Pylons` experience or experience in
- another framework which does not provide traversal, and need an
- introduction to the "why" of traversal.
+ chapter, which discusses technical details. This chapter is mostly aimed at
+ people who have previous :term:`Pylons` experience or experience in another
+ framework which does not provide traversal, and need an introduction to the
+ "why" of traversal.
Some folks who have been using Pylons and its Routes-based URL matching for a
long time are being exposed for the first time, via :app:`Pyramid`, to new
ideas such as ":term:`traversal`" and ":term:`view lookup`" as a way to route
incoming HTTP requests to callable code. Some of the same folks believe that
-traversal is hard to understand. Others question its usefulness; URL
-matching has worked for them so far, why should they even consider dealing
-with another approach, one which doesn't fit their brain and which doesn't
-provide any immediately obvious value?
+traversal is hard to understand. Others question its usefulness; URL matching
+has worked for them so far, so why should they even consider dealing with
+another approach, one which doesn't fit their brain and which doesn't provide
+any immediately obvious value?
You can be assured that if you don't want to understand traversal, you don't
have to. You can happily build :app:`Pyramid` applications with only
-:term:`URL dispatch`. However, there are some straightforward, real-world
-use cases that are much more easily served by a traversal-based approach than
-by a pattern-matching mechanism. Even if you haven't yet hit one of these
-use cases yourself, understanding these new ideas is worth the effort for any
-web developer so you know when you might want to use them. :term:`Traversal`
-is actually a straightforward metaphor easily comprehended by anyone who's
-ever used a run-of-the-mill file system with folders and files.
+:term:`URL dispatch`. However, there are some straightforward, real-world use
+cases that are much more easily served by a traversal-based approach than by a
+pattern-matching mechanism. Even if you haven't yet hit one of these use cases
+yourself, understanding these new ideas is worth the effort for any web
+developer so you know when you might want to use them. :term:`Traversal` is
+actually a straightforward metaphor easily comprehended by anyone who's ever
+used a run-of-the-mill file system with folders and files.
.. index::
single: URL dispatch
@@ -49,34 +49,33 @@ ever used a run-of-the-mill file system with folders and files.
URL Dispatch
------------
-Let's step back and consider the problem we're trying to solve. An
-HTTP request for a particular path has been routed to our web
-application. The requested path will possibly invoke a specific
-:term:`view callable` function defined somewhere in our app. We're
-trying to determine *which* callable function, if any, should be
-invoked for a given requested URL.
+Let's step back and consider the problem we're trying to solve. An HTTP
+request for a particular path has been routed to our web application. The
+requested path will possibly invoke a specific :term:`view callable` function
+defined somewhere in our app. We're trying to determine *which* callable
+function, if any, should be invoked for a given requested URL.
Many systems, including Pyramid, offer a simple solution. They offer the
-concept of "URL matching". URL matching approaches this problem by parsing
-the URL path and comparing the results to a set of registered "patterns",
-defined by a set of regular expressions, or some other URL path templating
-syntax. Each pattern is mapped to a callable function somewhere; if the
-request path matches a specific pattern, the associated function is called.
-If the request path matches more than one pattern, some conflict resolution
-scheme is used, usually a simple order precedence so that the first match
-will take priority over any subsequent matches. If a request path doesn't
-match any of the defined patterns, a "404 Not Found" response is returned.
-
-In Pyramid, we offer an implementation of URL matching which we call
-:term:`URL dispatch`. Using :app:`Pyramid` syntax, we might have a match
-pattern such as ``/{userid}/photos/{photoid}``, mapped to a ``photo_view()``
-function defined somewhere in our code. Then a request for a path such as
+concept of "URL matching". URL matching approaches this problem by parsing the
+URL path and comparing the results to a set of registered "patterns", defined
+by a set of regular expressions or some other URL path templating syntax. Each
+pattern is mapped to a callable function somewhere; if the request path matches
+a specific pattern, the associated function is called. If the request path
+matches more than one pattern, some conflict resolution scheme is used, usually
+a simple order precedence so that the first match will take priority over any
+subsequent matches. If a request path doesn't match any of the defined
+patterns, a "404 Not Found" response is returned.
+
+In Pyramid, we offer an implementation of URL matching which we call :term:`URL
+dispatch`. Using :app:`Pyramid` syntax, we might have a match pattern such as
+``/{userid}/photos/{photoid}``, mapped to a ``photo_view()`` function defined
+somewhere in our code. Then a request for a path such as
``/joeschmoe/photos/photo1`` would be a match, and the ``photo_view()``
function would be invoked to handle the request. Similarly,
-``/{userid}/blog/{year}/{month}/{postid}`` might map to a
-``blog_post_view()`` function, so ``/joeschmoe/blog/2010/12/urlmatching``
-would trigger the function, which presumably would know how to find and
-render the ``urlmatching`` blog post.
+``/{userid}/blog/{year}/{month}/{postid}`` might map to a ``blog_post_view()``
+function, so ``/joeschmoe/blog/2010/12/urlmatching`` would trigger the
+function, which presumably would know how to find and render the
+``urlmatching`` blog post.
Historical Refresher
--------------------
@@ -88,65 +87,64 @@ time when we didn't have fancy web frameworks like :term:`Pylons` and
:app:`Pyramid`. Instead, we had general purpose HTTP servers that primarily
served files off of a file system. The "root" of a given site mapped to a
particular folder somewhere on the file system. Each segment of the request
-URL path represented a subdirectory. The final path segment would be either
-a directory or a file, and once the server found the right file it would
-package it up in an HTTP response and send it back to the client. So serving
-up a request for ``/joeschmoe/photos/photo1`` literally meant that there was
-a ``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which
-in turn contained a ``photo1`` file. If at any point along the way we find
-that there is not a folder or file matching the requested path, we return a
-404 response.
+URL path represented a subdirectory. The final path segment would be either a
+directory or a file, and once the server found the right file it would package
+it up in an HTTP response and send it back to the client. So serving up a
+request for ``/joeschmoe/photos/photo1`` literally meant that there was a
+``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which in
+turn contained a ``photo1`` file. If at any point along the way we find that
+there is not a folder or file matching the requested path, we return a 404
+response.
As the web grew more dynamic, however, a little bit of extra complexity was
-added. Technologies such as CGI and HTTP server modules were developed.
-Files were still looked up on the file system, but if the file ended with
-(for example) ``.cgi`` or ``.php``, or if it lived in a special folder,
-instead of simply sending the file to the client the server would read the
-file, execute it using an interpreter of some sort, and then send the output
-from this process to the client as the final result. The server
-configuration specified which files would trigger some dynamic code, with the
-default case being to just serve the static file.
+added. Technologies such as CGI and HTTP server modules were developed. Files
+were still looked up on the file system, but if the file ended with (for
+example) ``.cgi`` or ``.php``, or if it lived in a special folder, instead of
+simply sending the file to the client the server would read the file, execute
+it using an interpreter of some sort, and then send the output from this
+process to the client as the final result. The server configuration specified
+which files would trigger some dynamic code, with the default case being to
+just serve the static file.
.. index::
single: traversal
-Traversal (aka Resource Location)
----------------------------------
+Traversal (a.k.a., Resource Location)
+-------------------------------------
Believe it or not, if you understand how serving files from a file system
works, you understand traversal. And if you understand that a server might do
-something different based on what type of file a given request specifies,
-then you understand view lookup.
+something different based on what type of file a given request specifies, then
+you understand view lookup.
The major difference between file system lookup and traversal is that a file
-system lookup steps through nested directories and files in a file system
-tree, while traversal steps through nested dictionary-type objects in a
-:term:`resource tree`. Let's take a detailed look at one of our example
-paths, so we can see what I mean:
-
-The path ``/joeschmoe/photos/photo1``, has four segments: ``/``,
-``joeschmoe``, ``photos`` and ``photo1``. With file system lookup we might
-have a root folder (``/``) containing a nested folder (``joeschmoe``), which
-contains another nested folder (``photos``), which finally contains a JPG
-file (``photo1``). With traversal, we instead have a dictionary-like root
-object. Asking for the ``joeschmoe`` key gives us another dictionary-like
-object. Asking this in turn for the ``photos`` key gives us yet another
-mapping object, which finally (hopefully) contains the resource that we're
-looking for within its values, referenced by the ``photo1`` key.
-
-In pure Python terms, then, the traversal or "resource location"
-portion of satisfying the ``/joeschmoe/photos/photo1`` request
-will look something like this pseudocode::
+system lookup steps through nested directories and files in a file system tree,
+while traversal steps through nested dictionary-type objects in a
+:term:`resource tree`. Let's take a detailed look at one of our example paths,
+so we can see what I mean.
+
+The path ``/joeschmoe/photos/photo1``, has four segments: ``/``, ``joeschmoe``,
+``photos`` and ``photo1``. With file system lookup we might have a root folder
+(``/``) containing a nested folder (``joeschmoe``), which contains another
+nested folder (``photos``), which finally contains a JPG file (``photo1``).
+With traversal, we instead have a dictionary-like root object. Asking for the
+``joeschmoe`` key gives us another dictionary-like object. Asking in turn for
+the ``photos`` key gives us yet another mapping object, which finally
+(hopefully) contains the resource that we're looking for within its values,
+referenced by the ``photo1`` key.
+
+In pure Python terms, then, the traversal or "resource location" portion of
+satisfying the ``/joeschmoe/photos/photo1`` request will look something like
+this pseudocode::
get_root()['joeschmoe']['photos']['photo1']
-``get_root()`` is some function that returns a root traversal
-:term:`resource`. If all of the specified keys exist, then the returned
-object will be the resource that is being requested, analogous to the JPG
-file that was retrieved in the file system example. If a :exc:`KeyError` is
-generated anywhere along the way, :app:`Pyramid` will return 404. (This
-isn't precisely true, as you'll see when we learn about view lookup below,
-but the basic idea holds.)
+``get_root()`` is some function that returns a root traversal :term:`resource`.
+If all of the specified keys exist, then the returned object will be the
+resource that is being requested, analogous to the JPG file that was retrieved
+in the file system example. If a :exc:`KeyError` is generated anywhere along
+the way, :app:`Pyramid` will return 404. (This isn't precisely true, as you'll
+see when we learn about view lookup below, but the basic idea holds.)
.. index::
single: resource
@@ -159,10 +157,10 @@ nested dictionary things? Where do these objects, these 'resources', live?
What *are* they?"
Since :app:`Pyramid` is not a highly opinionated framework, it makes no
-restriction on how a :term:`resource` is implemented; a developer can
-implement them as he wishes. One common pattern used is to persist all of
-the resources, including the root, in a database as a graph. The root object
-is a dictionary-like object. Dictionary-like objects in Python supply a
+restriction on how a :term:`resource` is implemented; a developer can implement
+them as they wish. One common pattern used is to persist all of the resources,
+including the root, in a database as a graph. The root object is a
+dictionary-like object. Dictionary-like objects in Python supply a
``__getitem__`` method which is called when key lookup is done. Under the
hood, when ``adict`` is a dictionary-like object, Python translates
``adict['a']`` to ``adict.__getitem__('a')``. Try doing this in a Python
@@ -175,25 +173,24 @@ interpreter prompt if you don't believe us:
>>> adict.__getitem__('a')
1
-
The dictionary-like root object stores the ids of all of its subresources as
keys, and provides a ``__getitem__`` implementation that fetches them. So
``get_root()`` fetches the unique root object, while
``get_root()['joeschmoe']`` returns a different object, also stored in the
database, which in turn has its own subresources and ``__getitem__``
-implementation, etc. These resources might be persisted in a relational
+implementation, and so on. These resources might be persisted in a relational
database, one of the many "NoSQL" solutions that are becoming popular these
-days, or anywhere else, it doesn't matter. As long as the returned objects
-provide the dictionary-like API (i.e. as long as they have an appropriately
-implemented ``__getitem__`` method) then traversal will work.
-
-In fact, you don't need a "database" at all. You could use plain
-dictionaries, with your site's URL structure hard-coded directly in
-the Python source. Or you could trivially implement a set of objects
-with ``__getitem__`` methods that search for files in specific
-directories, and thus precisely recreate the traditional mechanism of
-having the URL path mapped directly to a folder structure on the file
-system. Traversal is in fact a superset of file system lookup.
+days, or anywhere else; it doesn't matter. As long as the returned objects
+provide the dictionary-like API (i.e., as long as they have an appropriately
+implemented ``__getitem__`` method), then traversal will work.
+
+In fact, you don't need a "database" at all. You could use plain dictionaries,
+with your site's URL structure hard-coded directly in the Python source. Or
+you could trivially implement a set of objects with ``__getitem__`` methods
+that search for files in specific directories, and thus precisely recreate the
+traditional mechanism of having the URL path mapped directly to a folder
+structure on the file system. Traversal is in fact a superset of file system
+lookup.
.. note:: See the chapter entitled :ref:`resources_chapter` for a more
technical overview of resources.
@@ -208,34 +205,33 @@ At this point we're nearly there. We've covered traversal, which is the
process by which a specific resource is retrieved according to a specific URL
path. But what is "view lookup"?
-The need for view lookup is simple: there is more than one possible action
-that you might want to take after finding a :term:`resource`. With our photo
+The need for view lookup is simple: there is more than one possible action that
+you might want to take after finding a :term:`resource`. With our photo
example, for instance, you might want to view the photo in a page, but you
might also want to provide a way for the user to edit the photo and any
associated metadata. We'll call the former the ``view`` view, and the latter
will be the ``edit`` view. (Original, I know.) :app:`Pyramid` has a
centralized view :term:`application registry` where named views can be
-associated with specific resource types. So in our example, we'll assume
-that we've registered ``view`` and ``edit`` views for photo objects, and that
-we've specified the ``view`` view as the default, so that
+associated with specific resource types. So in our example, we'll assume that
+we've registered ``view`` and ``edit`` views for photo objects, and that we've
+specified the ``view`` view as the default, so that
``/joeschmoe/photos/photo1/view`` and ``/joeschmoe/photos/photo1`` are
equivalent. The edit view would sensibly be provided by a request for
``/joeschmoe/photos/photo1/edit``.
Hopefully it's clear that the first portion of the edit view's URL path is
-going to resolve to the same resource as the non-edit version, specifically
-the resource returned by ``get_root()['joeschmoe']['photos']['photo1']``.
-But traveral ends there; the ``photo1`` resource doesn't have an ``edit``
-key. In fact, it might not even be a dictionary-like object, in which case
+going to resolve to the same resource as the non-edit version, specifically the
+resource returned by ``get_root()['joeschmoe']['photos']['photo1']``. But
+traversal ends there; the ``photo1`` resource doesn't have an ``edit`` key. In
+fact, it might not even be a dictionary-like object, in which case
``photo1['edit']`` would be meaningless. When the :app:`Pyramid` resource
location has been resolved to a *leaf* resource, but the entire request path
has not yet been expended, the *very next* path segment is treated as a
-:term:`view name`. The registry is then checked to see if a view of the
-given name has been specified for a resource of the given type. If so, the
-view callable is invoked, with the resource passed in as the related
-``context`` object (also available as ``request.context``). If a view
-callable could not be found, :app:`Pyramid` will return a "404 Not Found"
-response.
+:term:`view name`. The registry is then checked to see if a view of the given
+name has been specified for a resource of the given type. If so, the view
+callable is invoked, with the resource passed in as the related ``context``
+object (also available as ``request.context``). If a view callable could not
+be found, :app:`Pyramid` will return a "404 Not Found" response.
You might conceptualize a request for ``/joeschmoe/photos/photo1/edit`` as
ultimately converted into the following piece of Pythonic pseudocode::
@@ -246,8 +242,8 @@ ultimately converted into the following piece of Pythonic pseudocode::
view_callable(request)
The ``get_root`` and ``get_view`` functions don't really exist. Internally,
-:app:`Pyramid` does something more complicated. But the example above
-is a reasonable approximation of the view lookup algorithm in pseudocode.
+:app:`Pyramid` does something more complicated. But the example above is a
+reasonable approximation of the view lookup algorithm in pseudocode.
Use Cases
---------
@@ -261,58 +257,57 @@ like this::
/{userid}/{typename}/{objectid}[/{view_name}]
-In all of the examples thus far, we've hard coded the typename value,
-assuming that we'd know at development time what names were going to be used
-("photos", "blog", etc.). But what if we don't know what these names will
-be? Or, worse yet, what if we don't know *anything* about the structure of
-the URLs inside a user's folder? We could be writing a CMS where we want the
-end user to be able to arbitrarily add content and other folders inside his
-folder. He might decide to nest folders dozens of layers deep. How will you
-construct matching patterns that could account for every possible combination
-of paths that might develop?
-
-It might be possible, but it certainly won't be easy. The matching
-patterns are going to become complex quickly as you try to handle all
-of the edge cases.
-
-With traversal, however, it's straightforward. Twenty layers of nesting
-would be no problem. :app:`Pyramid` will happily call ``__getitem__`` as
-many times as it needs to, until it runs out of path segments or until a
-resource raises a :exc:`KeyError`. Each resource only needs to know how to
-fetch its immediate children, the traversal algorithm takes care of the rest.
-Also, since the structure of the resource tree can live in the database and
-not in the code, it's simple to let users modify the tree at runtime to set
-up their own personalized "directory" structures.
-
-Another use case in which traversal shines is when there is a need to support
-a context-dependent security policy. One example might be a document
-management infrastructure for a large corporation, where members of different
-departments have varying access levels to the various other departments'
-files. Reasonably, even specific files might need to be made available to
-specific individuals. Traversal does well here if your resources actually
-represent the data objects related to your documents, because the idea of a
-resource authorization is baked right into the code resolution and calling
-process. Resource objects can store ACLs, which can be inherited and/or
-overridden by the subresources.
-
-If each resource can thus generate a context-based ACL, then whenever view
-code is attempting to perform a sensitive action, it can check against that
-ACL to see whether the current user should be allowed to perform the action.
-In this way you achieve so called "instance based" or "row level" security
-which is considerably harder to model using a traditional tabular approach.
+In all of the examples thus far, we've hard coded the typename value, assuming
+that we'd know at development time what names were going to be used ("photos",
+"blog", etc.). But what if we don't know what these names will be? Or, worse
+yet, what if we don't know *anything* about the structure of the URLs inside a
+user's folder? We could be writing a CMS where we want the end user to be able
+to arbitrarily add content and other folders inside his folder. He might
+decide to nest folders dozens of layers deep. How will you construct matching
+patterns that could account for every possible combination of paths that might
+develop?
+
+It might be possible, but it certainly won't be easy. The matching patterns
+are going to become complex quickly as you try to handle all of the edge cases.
+
+With traversal, however, it's straightforward. Twenty layers of nesting would
+be no problem. :app:`Pyramid` will happily call ``__getitem__`` as many times
+as it needs to, until it runs out of path segments or until a resource raises a
+:exc:`KeyError`. Each resource only needs to know how to fetch its immediate
+children, and the traversal algorithm takes care of the rest. Also, since the
+structure of the resource tree can live in the database and not in the code,
+it's simple to let users modify the tree at runtime to set up their own
+personalized "directory" structures.
+
+Another use case in which traversal shines is when there is a need to support a
+context-dependent security policy. One example might be a document management
+infrastructure for a large corporation, where members of different departments
+have varying access levels to the various other departments' files.
+Reasonably, even specific files might need to be made available to specific
+individuals. Traversal does well here if your resources actually represent the
+data objects related to your documents, because the idea of a resource
+authorization is baked right into the code resolution and calling process.
+Resource objects can store ACLs, which can be inherited and/or overridden by
+the subresources.
+
+If each resource can thus generate a context-based ACL, then whenever view code
+is attempting to perform a sensitive action, it can check against that ACL to
+see whether the current user should be allowed to perform the action. In this
+way you achieve so called "instance based" or "row level" security which is
+considerably harder to model using a traditional tabular approach.
:app:`Pyramid` actively supports such a scheme, and in fact if you register
-your views with guard permissions and use an authorization policy,
-:app:`Pyramid` can check against a resource's ACL when deciding whether or
-not the view itself is available to the current user.
+your views with guarded permissions and use an authorization policy,
+:app:`Pyramid` can check against a resource's ACL when deciding whether or not
+the view itself is available to the current user.
-In summary, there are entire classes of problems that are more easily served
-by traversal and view lookup than by :term:`URL dispatch`. If your problems
-don't require it, great: stick with :term:`URL dispatch`. But if you're
-using :app:`Pyramid` and you ever find that you *do* need to support one of
-these use cases, you'll be glad you have traversal in your toolkit.
+In summary, there are entire classes of problems that are more easily served by
+traversal and view lookup than by :term:`URL dispatch`. If your problems don't
+require it, great, stick with :term:`URL dispatch`. But if you're using
+:app:`Pyramid` and you ever find that you *do* need to support one of these use
+cases, you'll be glad you have traversal in your toolkit.
.. note::
- It is even possible to mix and match :term:`traversal` with
- :term:`URL dispatch` in the same :app:`Pyramid` application. See the
+ It is even possible to mix and match :term:`traversal` with :term:`URL
+ dispatch` in the same :app:`Pyramid` application. See the
:ref:`hybrid_chapter` chapter for details.
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 25f3931e9..5103bb6b8 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -53,15 +53,19 @@ The included scaffolds are these:
``alchemy``
URL mapping via :term:`URL dispatch` and persistence via :term:`SQLAlchemy`
+
.. index::
single: creating a project
single: project
+ single: pcreate
.. _creating_a_project:
Creating the Project
--------------------
+.. seealso:: See also the output of :ref:`pcreate --help <pcreate_script>`.
+
In :ref:`installing_chapter`, you created a virtual Python environment via the
``virtualenv`` command. To start a :app:`Pyramid` :term:`project`, use the
``pcreate`` command installed within the virtualenv. We'll choose the
@@ -77,7 +81,7 @@ The below example uses the ``pcreate`` command to create a project with the
On UNIX:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/pcreate -s starter MyProject
@@ -90,7 +94,7 @@ Or on Windows:
Here's sample output from a run of ``pcreate`` on UNIX for a project we name
``MyProject``:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/pcreate -s starter MyProject
Creating template pyramid
@@ -158,7 +162,7 @@ created project directory.
On UNIX:
-.. code-block:: text
+.. code-block:: bash
$ cd MyProject
$ $VENV/bin/python setup.py develop
@@ -172,7 +176,7 @@ Or on Windows:
Elided output from a run of this command on UNIX is shown below:
-.. code-block:: text
+.. code-block:: bash
$ cd MyProject
$ $VENV/bin/python setup.py develop
@@ -198,7 +202,7 @@ directory of your virtualenv).
On UNIX:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/python setup.py test -q
@@ -210,7 +214,7 @@ Or on Windows:
Here's sample output from a test run on UNIX:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/python setup.py test -q
running test
@@ -221,11 +225,23 @@ Here's sample output from a test run on UNIX:
writing dependency_links to MyProject.egg-info/dependency_links.txt
writing entry points to MyProject.egg-info/entry_points.txt
reading manifest file 'MyProject.egg-info/SOURCES.txt'
+ reading manifest template 'MANIFEST.in'
+ warning: no files found matching '*.cfg'
+ warning: no files found matching '*.rst'
+ warning: no files found matching '*.ico' under directory 'myproject'
+ warning: no files found matching '*.gif' under directory 'myproject'
+ warning: no files found matching '*.jpg' under directory 'myproject'
+ warning: no files found matching '*.txt' under directory 'myproject'
+ warning: no files found matching '*.mak' under directory 'myproject'
+ warning: no files found matching '*.mako' under directory 'myproject'
+ warning: no files found matching '*.js' under directory 'myproject'
+ warning: no files found matching '*.html' under directory 'myproject'
+ warning: no files found matching '*.xml' under directory 'myproject'
writing manifest file 'MyProject.egg-info/SOURCES.txt'
running build_ext
- ..
+ .
----------------------------------------------------------------------
- Ran 1 test in 0.108s
+ Ran 1 test in 0.008s
OK
@@ -250,13 +266,15 @@ single sample test exists.
Running the Project Application
-------------------------------
+.. seealso:: See also the output of :ref:`pserve --help <pserve_script>`.
+
Once a project is installed for development, you can run the application it
represents using the ``pserve`` command against the generated configuration
file. In our case, this file is named ``development.ini``.
On UNIX:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/pserve development.ini
@@ -268,38 +286,38 @@ On Windows:
Here's sample output from a run of ``pserve`` on UNIX:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/pserve development.ini
- Starting server in PID 16601.
- serving on http://0.0.0.0:6543
-
-When you use ``pserve`` to start the application implied by the default
-rendering of a scaffold, it will respond to requests on *all* IP addresses
-possessed by your system, not just requests to ``localhost``. This is what the
-``0.0.0.0`` in ``serving on http://0.0.0.0:6543`` means. The server will
-respond to requests made to ``127.0.0.1`` and on any external IP address. For
-example, your system might be configured to have an external IP address
-``192.168.1.50``. If that's the case, if you use a browser running on the same
-system as Pyramid, it will be able to access the application via
-``http://127.0.0.1:6543/`` as well as via ``http://192.168.1.50:6543/``.
-However, *other people* on other computers on the same network will also be
-able to visit your Pyramid application in their browser by visiting
-``http://192.168.1.50:6543/``.
-
-If you want to restrict access such that only a browser running on the same
-machine as Pyramid will be able to access your Pyramid application, edit the
+ Starting server in PID 16208.
+ serving on http://127.0.0.1:6543
+
+Access is restricted such that only a browser running on the same machine as
+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 ``host`` value in the
-``[server:main]`` section. Change it from ``0.0.0.0`` to ``127.0.0.1``. For
+``[server:main]`` section, changing it from ``127.0.0.1`` to ``0.0.0.0``. For
example:
.. code-block:: ini
[server:main]
use = egg:waitress#main
- host = 127.0.0.1
+ host = 0.0.0.0
port = 6543
+Now when you use ``pserve`` to start the application, it will respond to
+requests on *all* IP addresses possessed by your system, not just requests to
+``localhost``. This is what the ``0.0.0.0`` in
+``serving on http://0.0.0.0:6543`` means. The server will respond to requests
+made to ``127.0.0.1`` and on any external IP address. For example, your system
+might be configured to have an external IP address ``192.168.1.50``. If that's
+the case, if you use a browser running on the same system as Pyramid, it will
+be able to access the application via ``http://127.0.0.1:6543/`` as well as via
+``http://192.168.1.50:6543/``. However, *other people* on other computers on
+the same network will also be able to visit your Pyramid application in their
+browser by visiting ``http://192.168.1.50:6543/``.
+
You can change the port on which the server runs on by changing the same
portion of the ``development.ini`` file. For example, you can change the
``port = 6543`` line in the ``development.ini`` file's ``[server:main]``
@@ -347,7 +365,7 @@ For example, on UNIX:
$ $VENV/bin/pserve development.ini --reload
Starting subprocess with file monitor
Starting server in PID 16601.
- serving on http://0.0.0.0:6543
+ serving on http://127.0.0.1:6543
Now if you make a change to any of your project's ``.py`` files or ``.ini``
files, you'll see the server restart automatically:
@@ -357,7 +375,7 @@ files, you'll see the server restart automatically:
development.ini changed; reloading...
-------------------- Restarting --------------------
Starting server in PID 16602.
- serving on http://0.0.0.0:6543
+ serving on http://127.0.0.1:6543
Changes to template files (such as ``.pt`` or ``.mak`` files) won't cause the
server to restart. Changes to template files don't require a server restart as
@@ -579,18 +597,16 @@ file. The name ``main`` is a convention used by PasteDeploy signifying that it
is the default application.
The ``[server:main]`` section of the configuration file configures a WSGI
-server which listens on TCP port 6543. It is configured to listen on all
-interfaces (``0.0.0.0``). This means that any remote system which has TCP
-access to your system can see your Pyramid application.
+server which listens on TCP port 6543. It is configured to listen on localhost
+only (``127.0.0.1``).
.. _MyProject_ini_logging:
-The sections that live between the markers ``# Begin logging configuration``
-and ``# End logging configuration`` represent Python's standard library
-:mod:`logging` module configuration for your application. The sections between
-these two markers are passed to the `logging module's config file configuration
-engine <http://docs.python.org/howto/logging.html#configuring-logging>`_ when
-the ``pserve`` or ``pshell`` commands are executed. The default configuration
+The sections after ``# logging configuration`` represent Python's standard
+library :mod:`logging` module configuration for your application. These
+sections are passed to the `logging module's config file configuration engine
+<http://docs.python.org/howto/logging.html#configuring-logging>`_ when the
+``pserve`` or ``pshell`` commands are executed. The default configuration
sends application logging output to the standard error output of your terminal.
For more information about logging configuration, see :ref:`logging_chapter`.
@@ -680,8 +696,8 @@ testing, packaging, and distributing your application.
``setup.py`` is the de facto standard which Python developers use to
distribute their reusable code. You can read more about ``setup.py`` files
and their usage in the `Setuptools documentation
- <http://peak.telecommunity.com/DevCenter/setuptools>`_ and `The Hitchhiker's
- Guide to Packaging <http://guide.python-distribute.org/>`_.
+ <http://peak.telecommunity.com/DevCenter/setuptools>`_ and `Python Packaging
+ User Guide <https://packaging.python.org/en/latest/>`_.
Our generated ``setup.py`` looks like this:
@@ -912,7 +928,7 @@ The ``tests.py`` module includes unit tests for your application.
.. literalinclude:: MyProject/myproject/tests.py
:language: python
- :lines: 1-18
+ :lines: 1-17
:linenos:
This sample ``tests.py`` file has a single unit test defined within it. This
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index cc5baf05e..50e85813a 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -609,8 +609,8 @@ Pyramid supports overriding almost every aspect of its setup through its
:ref:`Conflict Resolution <automatic_conflict_resolution>` mechanism. This
means that, in most cases, overriding a renderer is as simple as using the
:meth:`pyramid.config.Configurator.add_renderer` method to redefine the
-template extension. For example, if you would like to override the ``.txt``
-extension to specify a new renderer, you could do the following:
+template extension. For example, if you would like to override the ``json``
+renderer to specify a new renderer, you could do the following:
.. code-block:: python
diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst
index 6139154ff..92139c0ff 100644
--- a/docs/narr/resources.rst
+++ b/docs/narr/resources.rst
@@ -3,50 +3,47 @@
Resources
=========
-A :term:`resource` is an object that represents a "place" in a tree
-related to your application. Every :app:`Pyramid` application has at
-least one resource object: the :term:`root` resource. Even if you don't
-define a root resource manually, a default one is created for you. The
-root resource is the root of a :term:`resource tree`. A resource tree
-is a set of nested dictionary-like objects which you can use to
-represent your website's structure.
+A :term:`resource` is an object that represents a "place" in a tree related to
+your application. Every :app:`Pyramid` application has at least one resource
+object: the :term:`root` resource. Even if you don't define a root resource
+manually, a default one is created for you. The root resource is the root of a
+:term:`resource tree`. A resource tree is a set of nested dictionary-like
+objects which you can use to represent your website's structure.
In an application which uses :term:`traversal` to map URLs to code, the
resource tree structure is used heavily to map each URL to a :term:`view
-callable`. When :term:`traversal` is used, :app:`Pyramid` will walk
-through the resource tree by traversing through its nested dictionary
-structure in order to find a :term:`context` resource. Once a context
-resource is found, the context resource and data in the request will be
-used to find a :term:`view callable`.
+callable`. When :term:`traversal` is used, :app:`Pyramid` will walk through
+the resource tree by traversing through its nested dictionary structure in
+order to find a :term:`context` resource. Once a context resource is found,
+the context resource and data in the request will be used to find a :term:`view
+callable`.
In an application which uses :term:`URL dispatch`, the resource tree is only
used indirectly, and is often "invisible" to the developer. In URL dispatch
applications, the resource "tree" is often composed of only the root resource
-by itself. This root resource sometimes has security declarations attached
-to it, but is not required to have any. In general, the resource tree is
-much less important in applications that use URL dispatch than applications
-that use traversal.
+by itself. This root resource sometimes has security declarations attached to
+it, but is not required to have any. In general, the resource tree is much
+less important in applications that use URL dispatch than applications that use
+traversal.
In "Zope-like" :app:`Pyramid` applications, resource objects also often store
data persistently, and offer methods related to mutating that persistent data.
-In these kinds of applications, resources not only represent the site
-structure of your website, but they become the :term:`domain model` of the
-application.
+In these kinds of applications, resources not only represent the site structure
+of your website, but they become the :term:`domain model` of the application.
Also:
- The ``context`` and ``containment`` predicate arguments to
:meth:`~pyramid.config.Configurator.add_view` (or a
- :func:`~pyramid.view.view_config` decorator) reference a resource class
- or resource :term:`interface`.
+ :func:`~pyramid.view.view_config` decorator) reference a resource class or
+ resource :term:`interface`.
- A :term:`root factory` returns a resource.
-- A resource is exposed to :term:`view` code as the :term:`context` of a
- view.
+- A resource is exposed to :term:`view` code as the :term:`context` of a view.
- Various helpful :app:`Pyramid` API methods expect a resource as an argument
- (e.g. :meth:`~pyramid.request.Request.resource_url` and others).
+ (e.g., :meth:`~pyramid.request.Request.resource_url` and others).
.. index::
single: resource tree
@@ -58,27 +55,26 @@ Also:
Defining a Resource Tree
------------------------
-When :term:`traversal` is used (as opposed to a purely :term:`url dispatch`
+When :term:`traversal` is used (as opposed to a purely :term:`URL dispatch`
based application), :app:`Pyramid` expects to be able to traverse a tree
-composed of resources (the :term:`resource tree`). Traversal begins at a
-root resource, and descends into the tree recursively, trying each resource's
+composed of resources (the :term:`resource tree`). Traversal begins at a root
+resource, and descends into the tree recursively, trying each resource's
``__getitem__`` method to resolve a path segment to another resource object.
-:app:`Pyramid` imposes the following policy on resource instances in the
-tree:
+:app:`Pyramid` imposes the following policy on resource instances in the tree:
-- A container resource (a resource which contains other resources) must
- supply a ``__getitem__`` method which is willing to resolve a unicode name
- to a sub-resource. If a sub-resource by a particular name does not exist
- in a container resource, ``__getitem__`` method of the container resource
- must raise a :exc:`KeyError`. If a sub-resource by that name *does* exist,
- the container's ``__getitem__`` should return the sub-resource.
+- A container resource (a resource which contains other resources) must supply
+ a ``__getitem__`` method which is willing to resolve a Unicode name to a
+ sub-resource. If a sub-resource by a particular name does not exist in a
+ container resource, the ``__getitem__`` method of the container resource must
+ raise a :exc:`KeyError`. If a sub-resource by that name *does* exist, the
+ container's ``__getitem__`` should return the sub-resource.
- Leaf resources, which do not contain other resources, must not implement a
``__getitem__``, or if they do, their ``__getitem__`` method must always
raise a :exc:`KeyError`.
-See :ref:`traversal_chapter` for more information about how traversal
-works against resource instances.
+See :ref:`traversal_chapter` for more information about how traversal works
+against resource instances.
Here's a sample resource tree, represented by a variable named ``root``:
@@ -90,8 +86,8 @@ Here's a sample resource tree, represented by a variable named ``root``:
root = Resource({'a':Resource({'b':Resource({'c':Resource()})})})
-The resource tree we've created above is represented by a dictionary-like
-root object which has a single child named ``'a'``. ``'a'`` has a single child
+The resource tree we've created above is represented by a dictionary-like root
+object which has a single child named ``'a'``. ``'a'`` has a single child
named ``'b'``, and ``'b'`` has a single child named ``'c'``, which has no
children. It is therefore possible to access the ``'c'`` leaf resource like so:
@@ -100,20 +96,20 @@ children. It is therefore possible to access the ``'c'`` leaf resource like so:
root['a']['b']['c']
-If you returned the above ``root`` object from a :term:`root factory`, the
-path ``/a/b/c`` would find the ``'c'`` object in the resource tree as the
-result of :term:`traversal`.
+If you returned the above ``root`` object from a :term:`root factory`, the path
+``/a/b/c`` would find the ``'c'`` object in the resource tree as the result of
+:term:`traversal`.
-In this example, each of the resources in the tree is of the same class.
-This is not a requirement. Resource elements in the tree can be of any type.
-We used a single class to represent all resources in the tree for the sake of
+In this example, each of the resources in the tree is of the same class. This
+is not a requirement. Resource elements in the tree can be of any type. We
+used a single class to represent all resources in the tree for the sake of
simplicity, but in a "real" app, the resources in the tree can be arbitrary.
-Although the example tree above can service a traversal, the resource
-instances in the above example are not aware of :term:`location`, so their
-utility in a "real" application is limited. To make best use of built-in
-:app:`Pyramid` API facilities, your resources should be "location-aware".
-The next section details how to make resources location-aware.
+Although the example tree above can service a traversal, the resource instances
+in the above example are not aware of :term:`location`, so their utility in a
+"real" application is limited. To make best use of built-in :app:`Pyramid` API
+facilities, your resources should be "location-aware". The next section details
+how to make resources location-aware.
.. index::
pair: location-aware; resource
@@ -125,16 +121,16 @@ Location-Aware Resources
In order for certain :app:`Pyramid` location, security, URL-generation, and
traversal APIs to work properly against the resources in a resource tree, all
-resources in the tree must be :term:`location` -aware. This means they must
+resources in the tree must be :term:`location`-aware. This means they must
have two attributes: ``__parent__`` and ``__name__``.
-The ``__parent__`` attribute of a location-aware resource should be a
-reference to the resource's parent resource instance in the tree. The
-``__name__`` attribute should be the name with which a resource's parent
-refers to the resource via ``__getitem__``.
+The ``__parent__`` attribute of a location-aware resource should be a reference
+to the resource's parent resource instance in the tree. The ``__name__``
+attribute should be the name with which a resource's parent refers to the
+resource via ``__getitem__``.
-The ``__parent__`` of the root resource should be ``None`` and its
-``__name__`` should be the empty string. For instance:
+The ``__parent__`` of the root resource should be ``None`` and its ``__name__``
+should be the empty string. For instance:
.. code-block:: python
:linenos:
@@ -143,18 +139,18 @@ The ``__parent__`` of the root resource should be ``None`` and its
__name__ = ''
__parent__ = None
-A resource returned from the root resource's ``__getitem__`` method should
-have a ``__parent__`` attribute that is a reference to the root resource, and
-its ``__name__`` attribute should match the name by which it is reachable via
-the root resource's ``__getitem__``. A container resource within the root
-resource should have a ``__getitem__`` that returns resources with a
-``__parent__`` attribute that points at the container, and these subobjects
-should have a ``__name__`` attribute that matches the name by which they are
-retrieved from the container via ``__getitem__``. This pattern continues
-recursively "up" the tree from the root.
+A resource returned from the root resource's ``__getitem__`` method should have
+a ``__parent__`` attribute that is a reference to the root resource, and its
+``__name__`` attribute should match the name by which it is reachable via the
+root resource's ``__getitem__``. A container resource within the root resource
+should have a ``__getitem__`` that returns resources with a ``__parent__``
+attribute that points at the container, and these sub-objects should have a
+``__name__`` attribute that matches the name by which they are retrieved from
+the container via ``__getitem__``. This pattern continues recursively "up" the
+tree from the root.
The ``__parent__`` attributes of each resource form a linked list that points
-"downwards" toward the root. This is analogous to the `..` entry in
+"downwards" toward the root. This is analogous to the ``..`` entry in
filesystem directories. If you follow the ``__parent__`` values from any
resource in the resource tree, you will eventually come to the root resource,
just like if you keep executing the ``cd ..`` filesystem command, eventually
@@ -162,44 +158,41 @@ you will reach the filesystem root directory.
.. warning::
- If your root resource has a ``__name__`` argument that is not
- ``None`` or the empty string, URLs returned by the
- :func:`~pyramid.request.Request.resource_url` function and paths generated
+ If your root resource has a ``__name__`` argument that is not ``None`` or
+ the empty string, URLs returned by the
+ :func:`~pyramid.request.Request.resource_url` function, and paths generated
by the :func:`~pyramid.traversal.resource_path` and
- :func:`~pyramid.traversal.resource_path_tuple` APIs will be generated
+ :func:`~pyramid.traversal.resource_path_tuple` APIs, will be generated
improperly. The value of ``__name__`` will be prepended to every path and
- URL generated (as opposed to a single leading slash or empty tuple
- element).
+ URL generated (as opposed to a single leading slash or empty tuple element).
.. sidebar:: For your convenience
- If you'd rather not manage the ``__name__`` and ``__parent__`` attributes
- of your resources "by hand", an add-on package named
+ If you'd rather not manage the ``__name__`` and ``__parent__`` attributes of
+ your resources "by hand", an add-on package named
:mod:`pyramid_traversalwrapper` can help.
In order to use this helper feature, you must first install the
:mod:`pyramid_traversalwrapper` package (available via PyPI), then register
- its ``ModelGraphTraverser`` as the traversal policy, rather than the
- default :app:`Pyramid` traverser. The package contains instructions for
- doing so.
-
- Once :app:`Pyramid` is configured with this feature, you will no longer
- need to manage the ``__parent__`` and ``__name__`` attributes on resource
- objects "by hand". Instead, as necessary, during traversal :app:`Pyramid`
- will wrap each resource (even the root resource) in a ``LocationProxy``
- which will dynamically assign a ``__name__`` and a ``__parent__`` to the
- traversed resource (based on the last traversed resource and the name
- supplied to ``__getitem__``). The root resource will have a ``__name__``
- attribute of ``None`` and a ``__parent__`` attribute of ``None``.
-
-Applications which use tree-walking :app:`Pyramid` APIs require
-location-aware resources. These APIs include (but are not limited to)
+ its ``ModelGraphTraverser`` as the traversal policy, rather than the default
+ :app:`Pyramid` traverser. The package contains instructions for doing so.
+
+ Once :app:`Pyramid` is configured with this feature, you will no longer need
+ to manage the ``__parent__`` and ``__name__`` attributes on resource objects
+ "by hand". Instead, as necessary during traversal, :app:`Pyramid` will wrap
+ each resource (even the root resource) in a ``LocationProxy``, which will
+ dynamically assign a ``__name__`` and a ``__parent__`` to the traversed
+ resource, based on the last traversed resource and the name supplied to
+ ``__getitem__``. The root resource will have a ``__name__`` attribute of
+ ``None`` and a ``__parent__`` attribute of ``None``.
+
+Applications which use tree-walking :app:`Pyramid` APIs require location-aware
+resources. These APIs include (but are not limited to)
:meth:`~pyramid.request.Request.resource_url`,
-:func:`~pyramid.traversal.find_resource`,
-:func:`~pyramid.traversal.find_root`,
+:func:`~pyramid.traversal.find_resource`, :func:`~pyramid.traversal.find_root`,
:func:`~pyramid.traversal.find_interface`,
:func:`~pyramid.traversal.resource_path`,
-:func:`~pyramid.traversal.resource_path_tuple`, or
+:func:`~pyramid.traversal.resource_path_tuple`,
:func:`~pyramid.traversal.traverse`, :func:`~pyramid.traversal.virtual_root`,
and (usually) :meth:`~pyramid.request.Request.has_permission` and
:func:`~pyramid.security.principals_allowed_by_permission`.
@@ -214,15 +207,15 @@ location-aware.
.. _generating_the_url_of_a_resource:
-Generating The URL Of A Resource
+Generating the URL of a Resource
--------------------------------
-If your resources are :term:`location` aware, you can use the
+If your resources are :term:`location`-aware, you can use the
:meth:`pyramid.request.Request.resource_url` API to generate a URL for the
resource. This URL will use the resource's position in the parent tree to
create a resource path, and it will prefix the path with the current
-application URL to form a fully-qualified URL with the scheme, host, port,
-and path. You can also pass extra arguments to
+application URL to form a fully-qualified URL with the scheme, host, port, and
+path. You can also pass extra arguments to
:meth:`~pyramid.request.Request.resource_url` to influence the generated URL.
The simplest call to :meth:`~pyramid.request.Request.resource_url` looks like
@@ -237,17 +230,17 @@ The ``request`` in the above example is an instance of a :app:`Pyramid`
:term:`request` object.
If the resource referred to as ``resource`` in the above example was the root
-resource, and the host that was used to contact the server was
-``example.com``, the URL generated would be ``http://example.com/``.
-However, if the resource was a child of the root resource named ``a``, the
-generated URL would be ``http://example.com/a/``.
+resource, and the host that was used to contact the server was ``example.com``,
+the URL generated would be ``http://example.com/``. However, if the resource
+was a child of the root resource named ``a``, the generated URL would be
+``http://example.com/a/``.
A slash is appended to all resource URLs when
-:meth:`~pyramid.request.Request.resource_url` is used to generate them in
-this simple manner, because resources are "places" in the hierarchy, and URLs
-are meant to be clicked on to be visited. Relative URLs that you include on
-HTML pages rendered as the result of the default view of a resource are more
-apt to be relative to these resources than relative to their parent.
+:meth:`~pyramid.request.Request.resource_url` is used to generate them in this
+simple manner, because resources are "places" in the hierarchy, and URLs are
+meant to be clicked on to be visited. Relative URLs that you include on HTML
+pages rendered as the result of the default view of a resource are more apt to
+be relative to these resources than relative to their parent.
You can also pass extra elements to
:meth:`~pyramid.request.Request.resource_url`:
@@ -258,12 +251,12 @@ You can also pass extra elements to
url = request.resource_url(resource, 'foo', 'bar')
If the resource referred to as ``resource`` in the above example was the root
-resource, and the host that was used to contact the server was
-``example.com``, the URL generated would be ``http://example.com/foo/bar``.
-Any number of extra elements can be passed to
-:meth:`~pyramid.request.Request.resource_url` as extra positional arguments.
-When extra elements are passed, they are appended to the resource's URL. A
-slash is not appended to the final segment when elements are passed.
+resource, and the host that was used to contact the server was ``example.com``,
+the URL generated would be ``http://example.com/foo/bar``. Any number of extra
+elements can be passed to :meth:`~pyramid.request.Request.resource_url` as
+extra positional arguments. When extra elements are passed, they are appended
+to the resource's URL. A slash is not appended to the final segment when
+elements are passed.
You can also pass a query string:
@@ -273,16 +266,16 @@ You can also pass a query string:
url = request.resource_url(resource, query={'a':'1'})
If the resource referred to as ``resource`` in the above example was the root
-resource, and the host that was used to contact the server was
-``example.com``, the URL generated would be ``http://example.com/?a=1``.
+resource, and the host that was used to contact the server was ``example.com``,
+the URL generated would be ``http://example.com/?a=1``.
When a :term:`virtual root` is active, the URL generated by
:meth:`~pyramid.request.Request.resource_url` for a resource may be "shorter"
than its physical tree path. See :ref:`virtual_root_support` for more
information about virtually rooting a resource.
-For more information about generating resource URLs, see the documentation
-for :meth:`pyramid.request.Request.resource_url`.
+For more information about generating resource URLs, see the documentation for
+:meth:`pyramid.request.Request.resource_url`.
.. index::
pair: resource URL generation; overriding
@@ -292,10 +285,10 @@ for :meth:`pyramid.request.Request.resource_url`.
Overriding Resource URL Generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If a resource object implements a ``__resource_url__`` method, this method
-will be called when :meth:`~pyramid.request.Request.resource_url` is called
-to generate a URL for the resource, overriding the default URL returned for
-the resource by :meth:`~pyramid.request.Request.resource_url`.
+If a resource object implements a ``__resource_url__`` method, this method will
+be called when :meth:`~pyramid.request.Request.resource_url` is called to
+generate a URL for the resource, overriding the default URL returned for the
+resource by :meth:`~pyramid.request.Request.resource_url`.
The ``__resource_url__`` hook is passed two arguments: ``request`` and
``info``. ``request`` is the :term:`request` object passed to
@@ -304,21 +297,21 @@ the following keys:
``physical_path``
A string representing the "physical path" computed for the resource, as
- defined by ``pyramid.traversal.resource_path(resource)``. It will begin
- and end with a slash.
+ defined by ``pyramid.traversal.resource_path(resource)``. It will begin and
+ end with a slash.
``virtual_path``
A string representing the "virtual path" computed for the resource, as
defined by :ref:`virtual_root_support`. This will be identical to the
- physical path if virtual rooting is not enabled. It will begin and end
- with a slash.
+ physical path if virtual rooting is not enabled. It will begin and end with
+ a slash.
``app_url``
A string representing the application URL generated during
``request.resource_url``. It will not end with a slash. It represents a
- potentially customized URL prefix, containing potentially custom scheme,
- host and port information passed by the user to ``request.resource_url``.
- It should be preferred over use of ``request.application_url``.
+ potentially customized URL prefix, containing potentially custom scheme, host
+ and port information passed by the user to ``request.resource_url``. It
+ should be preferred over use of ``request.application_url``.
The ``__resource_url__`` method of a resource should return a string
representing a URL. If it cannot override the default, it should return
@@ -335,12 +328,12 @@ Here's an example ``__resource_url__`` method.
The above example actually just generates and returns the default URL, which
would have been what was generated by the default ``resource_url`` machinery,
-but your code can perform arbitrary logic as necessary. For example, your
-code may wish to override the hostname or port number of the generated URL.
+but your code can perform arbitrary logic as necessary. For example, your code
+may wish to override the hostname or port number of the generated URL.
-Note that the URL generated by ``__resource_url__`` should be fully
-qualified, should end in a slash, and should not contain any query string or
-anchor elements (only path elements) to work with
+Note that the URL generated by ``__resource_url__`` should be fully qualified,
+should end in a slash, and should not contain any query string or anchor
+elements (only path elements) to work with
:meth:`~pyramid.request.Request.resource_url`.
.. index::
@@ -350,9 +343,8 @@ Generating the Path To a Resource
---------------------------------
:func:`pyramid.traversal.resource_path` returns a string object representing
-the absolute physical path of the resource object based on its position in
-the resource tree. Each segment of the path is separated with a slash
-character.
+the absolute physical path of the resource object based on its position in the
+resource tree. Each segment of the path is separated with a slash character.
.. code-block:: python
:linenos:
@@ -378,8 +370,8 @@ If ``resource`` in the example above was accessible in the tree as
The resource passed in must be :term:`location`-aware.
-The presence or absence of a :term:`virtual root` has no impact on the
-behavior of :func:`~pyramid.traversal.resource_path`.
+The presence or absence of a :term:`virtual root` has no impact on the behavior
+of :func:`~pyramid.traversal.resource_path`.
.. index::
pair: resource; finding by path
@@ -387,8 +379,8 @@ behavior of :func:`~pyramid.traversal.resource_path`.
Finding a Resource by Path
--------------------------
-If you have a string path to a resource, you can grab the resource from
-that place in the application's resource tree using
+If you have a string path to a resource, you can grab the resource from that
+place in the application's resource tree using
:func:`pyramid.traversal.find_resource`.
You can resolve an absolute path by passing a string prefixed with a ``/`` as
@@ -400,8 +392,9 @@ the ``path`` argument:
from pyramid.traversal import find_resource
url = find_resource(anyresource, '/path')
-Or you can resolve a path relative to the resource you pass in by passing a
-string that isn't prefixed by ``/``:
+Or you can resolve a path relative to the resource that you pass in to
+:func:`pyramid.traversal.find_resource` by passing a string that isn't prefixed
+by ``/``:
.. code-block:: python
:linenos:
@@ -410,8 +403,8 @@ string that isn't prefixed by ``/``:
url = find_resource(anyresource, 'path')
Often the paths you pass to :func:`~pyramid.traversal.find_resource` are
-generated by the :func:`~pyramid.traversal.resource_path` API. These APIs
-are "mirrors" of each other.
+generated by the :func:`~pyramid.traversal.resource_path` API. These APIs are
+"mirrors" of each other.
If the path cannot be resolved when calling
:func:`~pyramid.traversal.find_resource` (if the respective resource in the
@@ -427,10 +420,10 @@ Obtaining the Lineage of a Resource
-----------------------------------
:func:`pyramid.location.lineage` returns a generator representing the
-:term:`lineage` of the :term:`location` aware :term:`resource` object.
+:term:`lineage` of the :term:`location`-aware :term:`resource` object.
-The :func:`~pyramid.location.lineage` function returns the resource it is
-passed, then each parent of the resource, in order. For example, if the
+The :func:`~pyramid.location.lineage` function returns the resource that is
+passed into it, then each parent of the resource in order. For example, if the
resource tree is composed like so:
.. code-block:: python
@@ -451,18 +444,18 @@ list, we will get:
list(lineage(thing2))
[ <Thing object at thing2>, <Thing object at thing1> ]
-The generator returned by :func:`~pyramid.location.lineage` first returns the
-resource it was passed unconditionally. Then, if the resource supplied a
-``__parent__`` attribute, it returns the resource represented by
-``resource.__parent__``. If *that* resource has a ``__parent__`` attribute,
-return that resource's parent, and so on, until the resource being inspected
-either has no ``__parent__`` attribute or has a ``__parent__`` attribute of
-``None``.
+The generator returned by :func:`~pyramid.location.lineage` first returns
+unconditionally the resource that was passed into it. Then, if the resource
+supplied a ``__parent__`` attribute, it returns the resource represented by
+``resource.__parent__``. If *that* resource has a ``__parent__`` attribute, it
+will return that resource's parent, and so on, until the resource being
+inspected either has no ``__parent__`` attribute or has a ``__parent__``
+attribute of ``None``.
See the documentation for :func:`pyramid.location.lineage` for more
information.
-Determining if a Resource is In The Lineage of Another Resource
+Determining if a Resource is in the Lineage of Another Resource
---------------------------------------------------------------
Use the :func:`pyramid.location.inside` function to determine if one resource
@@ -479,12 +472,12 @@ For example, if the resource tree is:
b = Thing()
b.__parent__ = a
-Calling ``inside(b, a)`` will return ``True``, because ``b`` has a lineage
-that includes ``a``. However, calling ``inside(a, b)`` will return ``False``
+Calling ``inside(b, a)`` will return ``True``, because ``b`` has a lineage that
+includes ``a``. However, calling ``inside(a, b)`` will return ``False``
because ``a`` does not have a lineage that includes ``b``.
The argument list for :func:`~pyramid.location.inside` is ``(resource1,
-resource2)``. ``resource1`` is 'inside' ``resource2`` if ``resource2`` is a
+resource2)``. ``resource1`` is "inside" ``resource2`` if ``resource2`` is a
:term:`lineage` ancestor of ``resource1``. It is a lineage ancestor if its
parent (or one of its parent's parents, etc.) is an ancestor.
@@ -497,9 +490,9 @@ Finding the Root Resource
-------------------------
Use the :func:`pyramid.traversal.find_root` API to find the :term:`root`
-resource. The root resource is the root resource of the :term:`resource
-tree`. The API accepts a single argument: ``resource``. This is a resource
-that is :term:`location` aware. It can be any resource in the tree for which
+resource. The root resource is the resource at the root of the :term:`resource
+tree`. The API accepts a single argument: ``resource``. This is a resource
+that is :term:`location`-aware. It can be any resource in the tree for which
you want to find the root.
For example, if the resource tree is:
@@ -518,9 +511,9 @@ Calling ``find_root(b)`` will return ``a``.
The root resource is also available as ``request.root`` within :term:`view
callable` code.
-The presence or absence of a :term:`virtual root` has no impact on the
-behavior of :func:`~pyramid.traversal.find_root`. The root object returned
-is always the *physical* root object.
+The presence or absence of a :term:`virtual root` has no impact on the behavior
+of :func:`~pyramid.traversal.find_root`. The root object returned is always
+the *physical* root object.
.. index::
single: resource interfaces
@@ -531,19 +524,18 @@ Resources Which Implement Interfaces
------------------------------------
Resources can optionally be made to implement an :term:`interface`. An
-interface is used to tag a resource object with a "type" that can later be
+interface is used to tag a resource object with a "type" that later can be
referred to within :term:`view configuration` and by
:func:`pyramid.traversal.find_interface`.
Specifying an interface instead of a class as the ``context`` or
``containment`` predicate arguments within :term:`view configuration`
statements makes it possible to use a single view callable for more than one
-class of resource object. If your application is simple enough that you see
-no reason to want to do this, you can skip reading this section of the
-chapter.
+class of resource objects. If your application is simple enough that you see
+no reason to want to do this, you can skip reading this section of the chapter.
-For example, here's some code which describes a blog entry which also
-declares that the blog entry implements an :term:`interface`.
+For example, here's some code which describes a blog entry which also declares
+that the blog entry implements an :term:`interface`.
.. code-block:: python
:linenos:
@@ -577,10 +569,10 @@ resource implements an interface by using the
``BlogEntry`` resource implements the ``IBlogEntry`` interface.
You can also specify that a particular resource *instance* provides an
-interface, as opposed to its class. When you declare that a class implements
-an interface, all instances of that class will also provide that interface.
-However, you can also just say that a single object provides the interface.
-To do so, use the :func:`zope.interface.directlyProvides` function:
+interface as opposed to its class. When you declare that a class implements an
+interface, all instances of that class will also provide that interface.
+However, you can also just say that a single object provides the interface. To
+do so, use the :func:`zope.interface.directlyProvides` function:
.. code-block:: python
:linenos:
@@ -603,9 +595,9 @@ To do so, use the :func:`zope.interface.directlyProvides` function:
directlyProvides(entry, IBlogEntry)
:func:`zope.interface.directlyProvides` will replace any existing interface
-that was previously provided by an instance. If a resource object already
-has instance-level interface declarations that you don't want to replace, use
-the :func:`zope.interface.alsoProvides` function:
+that was previously provided by an instance. If a resource object already has
+instance-level interface declarations that you don't want to replace, use the
+:func:`zope.interface.alsoProvides` function:
.. code-block:: python
:linenos:
@@ -632,8 +624,8 @@ the :func:`zope.interface.alsoProvides` function:
directlyProvides(entry, IBlogEntry1)
alsoProvides(entry, IBlogEntry2)
-:func:`zope.interface.alsoProvides` will augment the set of interfaces
-directly provided by an instance instead of overwriting them like
+:func:`zope.interface.alsoProvides` will augment the set of interfaces directly
+provided by an instance instead of overwriting them like
:func:`zope.interface.directlyProvides` does.
For more information about how resource interfaces can be used by view
@@ -642,7 +634,7 @@ configuration, see :ref:`using_resource_interfaces`.
.. index::
pair: resource; finding by interface or class
-Finding a Resource With a Class or Interface in Lineage
+Finding a Resource with a Class or Interface in Lineage
-------------------------------------------------------
Use the :func:`~pyramid.traversal.find_interface` API to locate a parent that
@@ -662,18 +654,19 @@ For example, if your resource tree is composed as follows:
Calling ``find_interface(a, Thing1)`` will return the ``a`` resource because
``a`` is of class ``Thing1`` (the resource passed as the first argument is
-considered first, and is returned if the class or interface spec matches).
+considered first, and is returned if the class or interface specification
+matches).
Calling ``find_interface(b, Thing1)`` will return the ``a`` resource because
-``a`` is of class ``Thing1`` and ``a`` is the first resource in ``b``'s
-lineage of this class.
+``a`` is of class ``Thing1`` and ``a`` is the first resource in ``b``'s lineage
+of this class.
Calling ``find_interface(b, Thing2)`` will return the ``b`` resource.
-The second argument to find_interface may also be a :term:`interface` instead
-of a class. If it is an interface, each resource in the lineage is checked
-to see if the resource implements the specificed interface (instead of seeing
-if the resource is of a class).
+The second argument to ``find_interface`` may also be a :term:`interface`
+instead of a class. If it is an interface, each resource in the lineage is
+checked to see if the resource implements the specificed interface (instead of
+seeing if the resource is of a class).
.. seealso::
@@ -690,18 +683,17 @@ A resource object is used as the :term:`context` provided to a view. See
:ref:`traversal_chapter` and :ref:`urldispatch_chapter` for more information
about how a resource object becomes the context.
-The APIs provided by :ref:`traversal_module` are used against resource
-objects. These functions can be used to find the "path" of a resource, the
-root resource in a resource tree, or to generate a URL for a resource.
+The APIs provided by :ref:`traversal_module` are used against resource objects.
+These functions can be used to find the "path" of a resource, the root resource
+in a resource tree, or to generate a URL for a resource.
-The APIs provided by :ref:`location_module` are used against resources.
-These can be used to walk down a resource tree, or conveniently locate one
-resource "inside" another.
-
-Some APIs on the :class:`pyramid.request.Request` accept a resource object as a parameter.
-For example, the :meth:`~pyramid.request.Request.has_permission` API accepts a
-resource object as one of its arguments; the ACL is obtained from this
-resource or one of its ancestors. Other security related APIs on the
-:class:`pyramid.request.Request` class also accept :term:`context` as an argument,
-and a context is always a resource.
+The APIs provided by :ref:`location_module` are used against resources. These
+can be used to walk down a resource tree, or conveniently locate one resource
+"inside" another.
+Some APIs on the :class:`pyramid.request.Request` accept a resource object as a
+parameter. For example, the :meth:`~pyramid.request.Request.has_permission` API
+accepts a resource object as one of its arguments; the ACL is obtained from
+this resource or one of its ancestors. Other security related APIs on the
+:class:`pyramid.request.Request` class also accept :term:`context` as an
+argument, and a context is always a resource.
diff --git a/docs/narr/scaffolding.rst b/docs/narr/scaffolding.rst
index 4fcdeb537..164ceb3bf 100644
--- a/docs/narr/scaffolding.rst
+++ b/docs/narr/scaffolding.rst
@@ -4,8 +4,8 @@ Creating Pyramid Scaffolds
==========================
You can extend Pyramid by creating a :term:`scaffold` template. A scaffold
-template is useful if you'd like to distribute a customizable configuration
-of Pyramid to other users. Once you've created a scaffold, and someone has
+template is useful if you'd like to distribute a customizable configuration of
+Pyramid to other users. Once you've created a scaffold, and someone has
installed the distribution that houses the scaffold, they can use the
``pcreate`` script to create a custom version of your scaffold's template.
Pyramid itself uses scaffolds to allow people to bootstrap new projects. For
@@ -15,22 +15,22 @@ example, ``pcreate -s alchemy MyStuff`` causes Pyramid to render the
Basics
------
-A scaffold template is just a bunch of source files and directories on disk.
-A small definition class points at this directory; it is in turn pointed at
-by a :term:`setuptools` "entry point" which registers the scaffold so it can
-be found by the ``pcreate`` command.
+A scaffold template is just a bunch of source files and directories on disk. A
+small definition class points at this directory. It is in turn pointed at by a
+:term:`setuptools` "entry point" which registers the scaffold so it can be
+found by the ``pcreate`` command.
To create a scaffold template, create a Python :term:`distribution` to house
the scaffold which includes a ``setup.py`` that relies on the ``setuptools``
-package. See `Creating a Package
-<http://guide.python-distribute.org/creation.html>`_ for more information
-about how to do this. For the sake of example, we'll pretend the
-distribution you create is named ``CoolExtension``, and it has a package
-directory within it named ``coolextension``
+package. See `Packaging and Distributing Projects
+<https://packaging.python.org/en/latest/distributing/>`_ for more information
+about how to do this. For example, we'll pretend the distribution you create
+is named ``CoolExtension``, and it has a package directory within it named
+``coolextension``.
-Once you've created the distribution put a "scaffolds" directory within your
-distribution's package directory, and create a file within that directory
-named ``__init__.py`` with something like the following:
+Once you've created the distribution, put a "scaffolds" directory within your
+distribution's package directory, and create a file within that directory named
+``__init__.py`` with something like the following:
.. code-block:: python
:linenos:
@@ -54,12 +54,12 @@ As you create files and directories within the template directory, note that:
the string value of the variable named ``var`` provided to the scaffold.
- Files and directories with filenames that contain the string ``+var+`` will
- have that string replaced with the value of the ``var`` variable provided
- to the scaffold.
+ have that string replaced with the value of the ``var`` variable provided to
+ the scaffold.
- Files that start with a dot (e.g., ``.env``) are ignored and will not be
copied over to the destination directory. If you want to include a file with
- a leading dot then you must replace the dot with ``+dot+`` (e.g.,
+ a leading dot, then you must replace the dot with ``+dot+`` (e.g.,
``+dot+env``).
Otherwise, files and directories which live in the template directory will be
@@ -67,14 +67,14 @@ copied directly without modification to the ``pcreate`` output location.
The variables provided by the default ``PyramidTemplate`` include ``project``
(the project name provided by the user as an argument to ``pcreate``),
-``package`` (a lowercasing and normalizing of the project name provided by
-the user), ``random_string`` (a long random string), and ``package_logger``
-(the name of the package's logger).
+``package`` (a lowercasing and normalizing of the project name provided by the
+user), ``random_string`` (a long random string), and ``package_logger`` (the
+name of the package's logger).
See Pyramid's "scaffolds" package
-(https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for
-concrete examples of scaffold directories (``zodb``, ``alchemy``, and
-``starter``, for example).
+(https://github.com/Pylons/pyramid/tree/master/pyramid/scaffolds) for concrete
+examples of scaffold directories (``zodb``, ``alchemy``, and ``starter``, for
+example).
After you've created the template directory, add the following to the
``entry_points`` value of your distribution's ``setup.py``:
@@ -96,17 +96,16 @@ For example:
"""
)
-Run your distribution's ``setup.py develop`` or ``setup.py install``
-command. After that, you should be able to see your scaffolding template
-listed when you run ``pcreate -l``. It will be named ``coolextension``
-because that's the name we gave it in the entry point setup. Running
-``pcreate -s coolextension MyStuff`` will then render your scaffold to an
-output directory named ``MyStuff``.
+Run your distribution's ``setup.py develop`` or ``setup.py install`` command.
+After that, you should be able to see your scaffolding template listed when you
+run ``pcreate -l``. It will be named ``coolextension`` because that's the name
+we gave it in the entry point setup. Running ``pcreate -s coolextension
+MyStuff`` will then render your scaffold to an output directory named
+``MyStuff``.
-See the module documentation for :mod:`pyramid.scaffolds` for information
-about the API of the :class:`pyramid.scaffolds.Template` class and
-related classes. You can override methods of this class to get special
-behavior.
+See the module documentation for :mod:`pyramid.scaffolds` for information about
+the API of the :class:`pyramid.scaffolds.Template` class and related classes.
+You can override methods of this class to get special behavior.
Supporting Older Pyramid Versions
---------------------------------
@@ -139,21 +138,22 @@ defining your scaffold template:
And then in the setup.py of the package that contains your scaffold, define
the template as a target of both ``paste.paster_create_template`` (for
-``paster create``) and ``pyramid.scaffold`` (for ``pcreate``)::
+``paster create``) and ``pyramid.scaffold`` (for ``pcreate``).
- [paste.paster_create_template]
- coolextension=coolextension.scaffolds:CoolExtensionTemplate
- [pyramid.scaffold]
- coolextension=coolextension.scaffolds:CoolExtensionTemplate
+.. code-block:: ini
+
+ [paste.paster_create_template]
+ coolextension=coolextension.scaffolds:CoolExtensionTemplate
+ [pyramid.scaffold]
+ coolextension=coolextension.scaffolds:CoolExtensionTemplate
-Doing this hideousness will allow your scaffold to work as a ``paster
-create`` target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under
-1.3). If an invoker tries to run ``paster create`` against a scaffold
-defined this way under 1.3, an error is raised instructing them to use
-``pcreate`` instead.
+Doing this hideousness will allow your scaffold to work as a ``paster create``
+target (under 1.0, 1.1, or 1.2) or as a ``pcreate`` target (under 1.3). If an
+invoker tries to run ``paster create`` against a scaffold defined this way
+under 1.3, an error is raised instructing them to use ``pcreate`` instead.
-If you want only to support Pyramid 1.3 only, it's much cleaner, and the API
-is stable:
+If you want to support Pyramid 1.3 only, it's much cleaner, and the API is
+stable:
.. code-block:: python
:linenos:
@@ -164,17 +164,17 @@ is stable:
_template_dir = 'coolextension_scaffold'
summary = 'My cool_extension'
-You only need to specify a ``paste.paster_create_template`` entry point
-target in your ``setup.py`` if you want your scaffold to be consumable by
-users of Pyramid 1.0, 1.1, or 1.2. To support only 1.3, specifying only the
+You only need to specify a ``paste.paster_create_template`` entry point target
+in your ``setup.py`` if you want your scaffold to be consumable by users of
+Pyramid 1.0, 1.1, or 1.2. To support only 1.3, specifying only the
``pyramid.scaffold`` entry point is good enough. If you want to support both
-``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2
-and some older version), you'll need to define both.
+``paster create`` and ``pcreate`` (meaning you want to support Pyramid 1.2 and
+some older version), you'll need to define both.
Examples
--------
Existing third-party distributions which house scaffolding are available via
-:term:`PyPI`. The ``pyramid_jqm``, ``pyramid_zcml`` and ``pyramid_jinja2``
+:term:`PyPI`. The ``pyramid_jqm``, ``pyramid_zcml``, and ``pyramid_jinja2``
packages house scaffolds. You can install and examine these packages to see
how they work in the quest to develop your own scaffolding.
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 75f4dc7c5..7cbea113c 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -6,64 +6,59 @@
Security
========
-:app:`Pyramid` provides an optional, declarative, security system.
-Security in :app:`Pyramid` is separated into authentication and
-authorization. The two systems communicate via :term:`principal`
-identifiers. Authentication is merely the mechanism by which credentials
-provided in the :term:`request` are resolved to one or more
-:term:`principal` identifiers. These identifiers represent the users and
-groups that are in effect during the request. Authorization then determines
-access based on the :term:`principal` identifiers, the requested
+:app:`Pyramid` provides an optional, declarative, security system. Security in
+:app:`Pyramid` is separated into authentication and authorization. The two
+systems communicate via :term:`principal` identifiers. Authentication is merely
+the mechanism by which credentials provided in the :term:`request` are resolved
+to one or more :term:`principal` identifiers. These identifiers represent the
+users and groups that are in effect during the request. Authorization then
+determines access based on the :term:`principal` identifiers, the requested
:term:`permission`, and a :term:`context`.
-The :app:`Pyramid` authorization system
-can prevent a :term:`view` from being invoked based on an
-:term:`authorization policy`. Before a view is invoked, the
-authorization system can use the credentials in the :term:`request`
-along with the :term:`context` resource to determine if access will be
-allowed. Here's how it works at a high level:
+The :app:`Pyramid` authorization system can prevent a :term:`view` from being
+invoked based on an :term:`authorization policy`. Before a view is invoked, the
+authorization system can use the credentials in the :term:`request` along with
+the :term:`context` resource to determine if access will be allowed. Here's
+how it works at a high level:
-- A user may or may not have previously visited the application and
- supplied authentication credentials, including a :term:`userid`. If
- so, the application may have called
- :func:`pyramid.security.remember` to remember these.
+- A user may or may not have previously visited the application and supplied
+ authentication credentials, including a :term:`userid`. If so, the
+ application may have called :func:`pyramid.security.remember` to remember
+ these.
- A :term:`request` is generated when a user visits the application.
- Based on the request, a :term:`context` resource is located through
:term:`resource location`. A context is located differently depending on
- whether the application uses :term:`traversal` or :term:`URL dispatch`, but
- a context is ultimately found in either case. See
- the :ref:`urldispatch_chapter` chapter for more information.
+ whether the application uses :term:`traversal` or :term:`URL dispatch`, but a
+ context is ultimately found in either case. See the
+ :ref:`urldispatch_chapter` chapter for more information.
-- A :term:`view callable` is located by :term:`view lookup` using the
- context as well as other attributes of the request.
+- A :term:`view callable` is located by :term:`view lookup` using the context
+ as well as other attributes of the request.
-- If an :term:`authentication policy` is in effect, it is passed the
- request. It will return some number of :term:`principal` identifiers.
- To do this, the policy would need to determine the authenticated
- :term:`userid` present in the request.
+- If an :term:`authentication policy` is in effect, it is passed the request.
+ It will return some number of :term:`principal` identifiers. To do this, the
+ policy would need to determine the authenticated :term:`userid` present in
+ the request.
- If an :term:`authorization policy` is in effect and the :term:`view
- configuration` associated with the view callable that was found has
- a :term:`permission` associated with it, the authorization policy is
- passed the :term:`context`, some number of :term:`principal`
- identifiers returned by the authentication policy, and the
- :term:`permission` associated with the view; it will allow or deny
- access.
+ configuration` associated with the view callable that was found has a
+ :term:`permission` associated with it, the authorization policy is passed the
+ :term:`context`, some number of :term:`principal` identifiers returned by the
+ authentication policy, and the :term:`permission` associated with the view;
+ it will allow or deny access.
-- If the authorization policy allows access, the view callable is
- invoked.
+- If the authorization policy allows access, the view callable is invoked.
-- If the authorization policy denies access, the view callable is not
- invoked; instead the :term:`forbidden view` is invoked.
+- If the authorization policy denies access, the view callable is not invoked.
+ Instead the :term:`forbidden view` is invoked.
Authorization is enabled by modifying your application to include an
-:term:`authentication policy` and :term:`authorization policy`.
-:app:`Pyramid` comes with a variety of implementations of these
-policies. To provide maximal flexibility, :app:`Pyramid` also
-allows you to create custom authentication policies and authorization
-policies.
+:term:`authentication policy` and :term:`authorization policy`. :app:`Pyramid`
+comes with a variety of implementations of these policies. To provide maximal
+flexibility, :app:`Pyramid` also allows you to create custom authentication
+policies and authorization policies.
.. index::
single: authorization policy
@@ -73,23 +68,22 @@ policies.
Enabling an Authorization Policy
--------------------------------
-:app:`Pyramid` does not enable any authorization policy by default. All
-views are accessible by completely anonymous users. In order to begin
-protecting views from execution based on security settings, you need
-to enable an authorization policy.
+:app:`Pyramid` does not enable any authorization policy by default. All views
+are accessible by completely anonymous users. In order to begin protecting
+views from execution based on security settings, you need to enable an
+authorization policy.
Enabling an Authorization Policy Imperatively
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Use the :meth:`~pyramid.config.Configurator.set_authorization_policy` method
-of the :class:`~pyramid.config.Configurator` to enable an authorization
-policy.
+Use the :meth:`~pyramid.config.Configurator.set_authorization_policy` method of
+the :class:`~pyramid.config.Configurator` to enable an authorization policy.
You must also enable an :term:`authentication policy` in order to enable the
-authorization policy. This is because authorization, in general, depends
-upon authentication. Use the
-:meth:`~pyramid.config.Configurator.set_authentication_policy` method
-during application setup to specify the authentication policy.
+authorization policy. This is because authorization, in general, depends upon
+authentication. Use the
+:meth:`~pyramid.config.Configurator.set_authentication_policy` method during
+application setup to specify the authentication policy.
For example:
@@ -105,28 +99,27 @@ For example:
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
-.. note:: The ``authentication_policy`` and ``authorization_policy``
- arguments may also be passed to their respective methods mentioned above
- as :term:`dotted Python name` values, each representing the dotted name
- path to a suitable implementation global defined at Python module scope.
+.. note:: The ``authentication_policy`` and ``authorization_policy`` arguments
+ may also be passed to their respective methods mentioned above as
+ :term:`dotted Python name` values, each representing the dotted name path to
+ a suitable implementation global defined at Python module scope.
The above configuration enables a policy which compares the value of an "auth
ticket" cookie passed in the request's environment which contains a reference
-to a single :term:`userid` and matches that userid's
-:term:`principals <principal>` against the principals present in any
-:term:`ACL` found in the resource tree when attempting to call some
-:term:`view`.
+to a single :term:`userid`, and matches that userid's :term:`principals
+<principal>` against the principals present in any :term:`ACL` found in the
+resource tree when attempting to call some :term:`view`.
While it is possible to mix and match different authentication and
-authorization policies, it is an error to configure a Pyramid application
-with an authentication policy but without the authorization policy or vice
-versa. If you do this, you'll receive an error at application startup time.
+authorization policies, it is an error to configure a Pyramid application with
+an authentication policy but without the authorization policy or vice versa. If
+you do this, you'll receive an error at application startup time.
.. seealso::
- See also the :mod:`pyramid.authorization` and
- :mod:`pyramid.authentication` modules for alternate implementations of
- authorization and authentication policies.
+ See also the :mod:`pyramid.authorization` and :mod:`pyramid.authentication`
+ modules for alternative implementations of authorization and authentication
+ policies.
.. index::
single: permissions
@@ -139,14 +132,13 @@ Protecting Views with Permissions
To protect a :term:`view callable` from invocation based on a user's security
settings when a particular type of resource becomes the :term:`context`, you
-must pass a :term:`permission` to :term:`view configuration`. Permissions
-are usually just strings, and they have no required composition: you can name
+must pass a :term:`permission` to :term:`view configuration`. Permissions are
+usually just strings, and they have no required composition: you can name
permissions whatever you like.
For example, the following view declaration protects the view named
``add_entry.html`` when the context resource is of type ``Blog`` with the
-``add`` permission using the :meth:`pyramid.config.Configurator.add_view`
-API:
+``add`` permission using the :meth:`pyramid.config.Configurator.add_view` API:
.. code-block:: python
:linenos:
@@ -158,8 +150,8 @@ API:
context='mypackage.resources.Blog',
permission='add')
-The equivalent view registration including the ``add`` permission name
-may be performed via the ``@view_config`` decorator:
+The equivalent view registration including the ``add`` permission name may be
+performed via the ``@view_config`` decorator:
.. code-block:: python
:linenos:
@@ -173,11 +165,11 @@ may be performed via the ``@view_config`` decorator:
pass
As a result of any of these various view configuration statements, if an
-authorization policy is in place when the view callable is found during
-normal application operations, the requesting user will need to possess the
-``add`` permission against the :term:`context` resource in order to be able
-to invoke the ``blog_entry_add_view`` view. If he does not, the
-:term:`Forbidden view` will be invoked.
+authorization policy is in place when the view callable is found during normal
+application operations, the requesting user will need to possess the ``add``
+permission against the :term:`context` resource in order to be able to invoke
+the ``blog_entry_add_view`` view. If they do not, the :term:`Forbidden view`
+will be invoked.
.. index::
pair: permission; default
@@ -187,18 +179,17 @@ to invoke the ``blog_entry_add_view`` view. If he does not, the
Setting a Default Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If a permission is not supplied to a view configuration, the registered
-view will always be executable by entirely anonymous users: any
-authorization policy in effect is ignored.
+If a permission is not supplied to a view configuration, the registered view
+will always be executable by entirely anonymous users: any authorization policy
+in effect is ignored.
-In support of making it easier to configure applications which are
-"secure by default", :app:`Pyramid` allows you to configure a
-*default* permission. If supplied, the default permission is used as
-the permission string to all view registrations which don't otherwise
-name a ``permission`` argument.
+In support of making it easier to configure applications which are "secure by
+default", :app:`Pyramid` allows you to configure a *default* permission. If
+supplied, the default permission is used as the permission string to all view
+registrations which don't otherwise name a ``permission`` argument.
-The :meth:`pyramid.config.Configurator.set_default_permission` method
-supports configuring a default permission for an application.
+The :meth:`pyramid.config.Configurator.set_default_permission` method supports
+configuring a default permission for an application.
When a default permission is registered:
@@ -207,8 +198,8 @@ When a default permission is registered:
view-configuration-named permission is used.
- If a view configuration names the permission
- :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission
- is ignored, and the view is registered *without* a permission (making it
+ :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission is
+ ignored, and the view is registered *without* a permission (making it
available to all callers regardless of their credentials).
.. warning::
@@ -226,19 +217,18 @@ When a default permission is registered:
.. _assigning_acls:
-Assigning ACLs to your Resource Objects
+Assigning ACLs to Your Resource Objects
---------------------------------------
-When the default :app:`Pyramid` :term:`authorization policy` determines
-whether a user possesses a particular permission with respect to a resource,
-it examines the :term:`ACL` associated with the resource. An ACL is
-associated with a resource by adding an ``__acl__`` attribute to the resource
-object. This attribute can be defined on the resource *instance* if you need
+When the default :app:`Pyramid` :term:`authorization policy` determines whether
+a user possesses a particular permission with respect to a resource, it
+examines the :term:`ACL` associated with the resource. An ACL is associated
+with a resource by adding an ``__acl__`` attribute to the resource object.
+This attribute can be defined on the resource *instance* if you need
instance-level security, or it can be defined on the resource *class* if you
just need type-level security.
-For example, an ACL might be attached to the resource for a blog via its
-class:
+For example, an ACL might be attached to the resource for a blog via its class:
.. code-block:: python
:linenos:
@@ -273,11 +263,11 @@ Or, if your resources are persistent, an ACL might be specified via the
(Allow, 'group:editors', 'edit'),
]
-Whether an ACL is attached to a resource's class or an instance of the
-resource itself, the effect is the same. It is useful to decorate individual
-resource instances with an ACL (as opposed to just decorating their class) in
-applications such as "CMS" systems where fine-grained access is required on
-an object-by-object basis.
+Whether an ACL is attached to a resource's class or an instance of the resource
+itself, the effect is the same. It is useful to decorate individual resource
+instances with an ACL (as opposed to just decorating their class) in
+applications such as content management systems where fine-grained access is
+required on an object-by-object basis.
Dynamic ACLs are also possible by turning the ACL into a callable on the
resource. This may allow the ACL to dynamically generate rules based on
@@ -321,30 +311,27 @@ Here's an example ACL:
(Allow, 'group:editors', 'edit'),
]
-The example ACL indicates that the
-:data:`pyramid.security.Everyone` principal -- a special
-system-defined principal indicating, literally, everyone -- is allowed
-to view the blog, the ``group:editors`` principal is allowed to add to
-and edit the blog.
+The example ACL indicates that the :data:`pyramid.security.Everyone`
+principal—a special system-defined principal indicating, literally, everyone—is
+allowed to view the blog, and the ``group:editors`` principal is allowed to add
+to and edit the blog.
-Each element of an ACL is an :term:`ACE` or access control entry.
-For example, in the above code block, there are three ACEs: ``(Allow,
-Everyone, 'view')``, ``(Allow, 'group:editors', 'add')``, and
-``(Allow, 'group:editors', 'edit')``.
+Each element of an ACL is an :term:`ACE`, or access control entry. For example,
+in the above code block, there are three ACEs: ``(Allow, Everyone, 'view')``,
+``(Allow, 'group:editors', 'add')``, and ``(Allow, 'group:editors', 'edit')``.
-The first element of any ACE is either
-:data:`pyramid.security.Allow`, or
-:data:`pyramid.security.Deny`, representing the action to take when
-the ACE matches. The second element is a :term:`principal`. The
-third argument is a permission or sequence of permission names.
+The first element of any ACE is either :data:`pyramid.security.Allow`, or
+:data:`pyramid.security.Deny`, representing the action to take when the ACE
+matches. The second element is a :term:`principal`. The third argument is a
+permission or sequence of permission names.
A principal is usually a user id, however it also may be a group id if your
authentication system provides group information and the effective
:term:`authentication policy` policy is written to respect group information.
See :ref:`extending_default_authentication_policies`.
-Each ACE in an ACL is processed by an authorization policy *in the
-order dictated by the ACL*. So if you have an ACL like this:
+Each ACE in an ACL is processed by an authorization policy *in the order
+dictated by the ACL*. So if you have an ACL like this:
.. code-block:: python
:linenos:
@@ -358,10 +345,9 @@ order dictated by the ACL*. So if you have an ACL like this:
(Deny, Everyone, 'view'),
]
-The default authorization policy will *allow* everyone the view
-permission, even though later in the ACL you have an ACE that denies
-everyone the view permission. On the other hand, if you have an ACL
-like this:
+The default authorization policy will *allow* everyone the view permission,
+even though later in the ACL you have an ACE that denies everyone the view
+permission. On the other hand, if you have an ACL like this:
.. code-block:: python
:linenos:
@@ -375,14 +361,13 @@ like this:
(Allow, Everyone, 'view'),
]
-The authorization policy will deny everyone the view permission, even
-though later in the ACL is an ACE that allows everyone.
+The authorization policy will deny everyone the view permission, even though
+later in the ACL, there is an ACE that allows everyone.
-The third argument in an ACE can also be a sequence of permission
-names instead of a single permission name. So instead of creating
-multiple ACEs representing a number of different permission grants to
-a single ``group:editors`` group, we can collapse this into a single
-ACE, as below.
+The third argument in an ACE can also be a sequence of permission names instead
+of a single permission name. So instead of creating multiple ACEs representing
+a number of different permission grants to a single ``group:editors`` group, we
+can collapse this into a single ACE, as below.
.. code-block:: python
:linenos:
@@ -403,23 +388,21 @@ ACE, as below.
Special Principal Names
-----------------------
-Special principal names exist in the :mod:`pyramid.security`
-module. They can be imported for use in your own code to populate
-ACLs, e.g. :data:`pyramid.security.Everyone`.
+Special principal names exist in the :mod:`pyramid.security` module. They can
+be imported for use in your own code to populate ACLs, e.g.,
+:data:`pyramid.security.Everyone`.
:data:`pyramid.security.Everyone`
- Literally, everyone, no matter what. This object is actually a
- string "under the hood" (``system.Everyone``). Every user "is" the
- principal named Everyone during every request, even if a security
- policy is not in use.
+ Literally, everyone, no matter what. This object is actually a string under
+ the hood (``system.Everyone``). Every user *is* the principal named
+ "Everyone" during every request, even if a security policy is not in use.
:data:`pyramid.security.Authenticated`
- Any user with credentials as determined by the current security
- policy. You might think of it as any user that is "logged in".
- This object is actually a string "under the hood"
- (``system.Authenticated``).
+ Any user with credentials as determined by the current security policy. You
+ might think of it as any user that is "logged in". This object is actually a
+ string under the hood (``system.Authenticated``).
.. index::
single: permission names
@@ -428,19 +411,19 @@ ACLs, e.g. :data:`pyramid.security.Everyone`.
Special Permissions
-------------------
-Special permission names exist in the :mod:`pyramid.security`
-module. These can be imported for use in ACLs.
+Special permission names exist in the :mod:`pyramid.security` module. These
+can be imported for use in ACLs.
.. _all_permissions:
:data:`pyramid.security.ALL_PERMISSIONS`
- An object representing, literally, *all* permissions. Useful in an
- ACL like so: ``(Allow, 'fred', ALL_PERMISSIONS)``. The
- ``ALL_PERMISSIONS`` object is actually a stand-in object that has a
- ``__contains__`` method that always returns ``True``, which, for all
- known authorization policies, has the effect of indicating that a
- given principal "has" any permission asked for by the system.
+ An object representing, literally, *all* permissions. Useful in an ACL like
+ so: ``(Allow, 'fred', ALL_PERMISSIONS)``. The ``ALL_PERMISSIONS`` object is
+ actually a stand-in object that has a ``__contains__`` method that always
+ returns ``True``, which, for all known authorization policies, has the effect
+ of indicating that a given principal has any permission asked for by the
+ system.
.. index::
single: special ACE
@@ -451,11 +434,11 @@ Special ACEs
A convenience :term:`ACE` is defined representing a deny to everyone of all
permissions in :data:`pyramid.security.DENY_ALL`. This ACE is often used as
-the *last* ACE of an ACL to explicitly cause inheriting authorization
-policies to "stop looking up the traversal tree" (effectively breaking any
-inheritance). For example, an ACL which allows *only* ``fred`` the view
-permission for a particular resource despite what inherited ACLs may say when
-the default authorization policy is in effect might look like so:
+the *last* ACE of an ACL to explicitly cause inheriting authorization policies
+to "stop looking up the traversal tree" (effectively breaking any inheritance).
+For example, an ACL which allows *only* ``fred`` the view permission for a
+particular resource, despite what inherited ACLs may say when the default
+authorization policy is in effect, might look like so:
.. code-block:: python
:linenos:
@@ -465,8 +448,8 @@ the default authorization policy is in effect might look like so:
__acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ]
-"Under the hood", the :data:`pyramid.security.DENY_ALL` ACE equals
-the following:
+Under the hood, the :data:`pyramid.security.DENY_ALL` ACE equals the
+following:
.. code-block:: python
:linenos:
@@ -483,14 +466,14 @@ ACL Inheritance and Location-Awareness
While the default :term:`authorization policy` is in place, if a resource
object does not have an ACL when it is the context, its *parent* is consulted
-for an ACL. If that object does not have an ACL, *its* parent is consulted
-for an ACL, ad infinitum, until we've reached the root and there are no more
+for an ACL. If that object does not have an ACL, *its* parent is consulted for
+an ACL, ad infinitum, until we've reached the root and there are no more
parents left.
In order to allow the security machinery to perform ACL inheritance, resource
objects must provide *location-awareness*. Providing *location-awareness*
-means two things: the root object in the resource tree must have a
-``__name__`` attribute and a ``__parent__`` attribute.
+means two things: the root object in the resource tree must have a ``__name__``
+attribute and a ``__parent__`` attribute.
.. code-block:: python
:linenos:
@@ -499,10 +482,10 @@ means two things: the root object in the resource tree must have a
__name__ = ''
__parent__ = None
-An object with a ``__parent__`` attribute and a ``__name__`` attribute
-is said to be *location-aware*. Location-aware objects define an
-``__parent__`` attribute which points at their parent object. The
-root object's ``__parent__`` is ``None``.
+An object with a ``__parent__`` attribute and a ``__name__`` attribute is said
+to be *location-aware*. Location-aware objects define a ``__parent__``
+attribute which points at their parent object. The root object's
+``__parent__`` is ``None``.
.. seealso::
@@ -519,12 +502,11 @@ root object's ``__parent__`` is ``None``.
Changing the Forbidden View
---------------------------
-When :app:`Pyramid` denies a view invocation due to an
-authorization denial, the special ``forbidden`` view is invoked. "Out
-of the box", this forbidden view is very plain. See
-:ref:`changing_the_forbidden_view` within :ref:`hooks_chapter` for
-instructions on how to create a custom forbidden view and arrange for
-it to be called when view authorization is denied.
+When :app:`Pyramid` denies a view invocation due to an authorization denial,
+the special ``forbidden`` view is invoked. Out of the box, this forbidden view
+is very plain. See :ref:`changing_the_forbidden_view` within
+:ref:`hooks_chapter` for instructions on how to create a custom forbidden view
+and arrange for it to be called when view authorization is denied.
.. index::
single: debugging authorization failures
@@ -534,8 +516,8 @@ it to be called when view authorization is denied.
Debugging View Authorization Failures
-------------------------------------
-If your application in your judgment is allowing or denying view
-access inappropriately, start your application under a shell using the
+If your application in your judgment is allowing or denying view access
+inappropriately, start your application under a shell using the
``PYRAMID_DEBUG_AUTHORIZATION`` environment variable set to ``1``. For
example:
@@ -543,14 +525,13 @@ example:
$ PYRAMID_DEBUG_AUTHORIZATION=1 $VENV/bin/pserve myproject.ini
-When any authorization takes place during a top-level view rendering,
-a message will be logged to the console (to stderr) about what ACE in
-which ACL permitted or denied the authorization based on
-authentication information.
+When any authorization takes place during a top-level view rendering, a message
+will be logged to the console (to stderr) about what ACE in which ACL permitted
+or denied the authorization based on authentication information.
-This behavior can also be turned on in the application ``.ini`` file
-by setting the ``pyramid.debug_authorization`` key to ``true`` within the
-application's configuration section, e.g.:
+This behavior can also be turned on in the application ``.ini`` file by setting
+the ``pyramid.debug_authorization`` key to ``true`` within the application's
+configuration section, e.g.:
.. code-block:: ini
:linenos:
@@ -559,26 +540,24 @@ application's configuration section, e.g.:
use = egg:MyProject
pyramid.debug_authorization = true
-With this debug flag turned on, the response sent to the browser will
-also contain security debugging information in its body.
+With this debug flag turned on, the response sent to the browser will also
+contain security debugging information in its body.
Debugging Imperative Authorization Failures
-------------------------------------------
The :meth:`pyramid.request.Request.has_permission` API is used to check
-security within view functions imperatively. It returns instances of
-objects that are effectively booleans. But these objects are not raw
-``True`` or ``False`` objects, and have information attached to them
-about why the permission was allowed or denied. The object will be
-one of :data:`pyramid.security.ACLAllowed`,
-:data:`pyramid.security.ACLDenied`,
-:data:`pyramid.security.Allowed`, or
-:data:`pyramid.security.Denied`, as documented in
-:ref:`security_module`. At the very minimum these objects will have a
-``msg`` attribute, which is a string indicating why the permission was
-denied or allowed. Introspecting this information in the debugger or
-via print statements when a call to
-:meth:`~pyramid.request.Request.has_permission` fails is often useful.
+security within view functions imperatively. It returns instances of objects
+that are effectively booleans. But these objects are not raw ``True`` or
+``False`` objects, and have information attached to them about why the
+permission was allowed or denied. The object will be one of
+:data:`pyramid.security.ACLAllowed`, :data:`pyramid.security.ACLDenied`,
+:data:`pyramid.security.Allowed`, or :data:`pyramid.security.Denied`, as
+documented in :ref:`security_module`. At the very minimum, these objects will
+have a ``msg`` attribute, which is a string indicating why the permission was
+denied or allowed. Introspecting this information in the debugger or via print
+statements when a call to :meth:`~pyramid.request.Request.has_permission` fails
+is often useful.
.. index::
single: authentication policy (extending)
@@ -588,27 +567,26 @@ via print statements when a call to
Extending Default Authentication Policies
-----------------------------------------
-Pyramid ships with some builtin authentication policies for use in your
-applications. See :mod:`pyramid.authentication` for the available
-policies. They differ on their mechanisms for tracking authentication
-credentials between requests, however they all interface with your
-application in mostly the same way.
+Pyramid ships with some built in authentication policies for use in your
+applications. See :mod:`pyramid.authentication` for the available policies.
+They differ on their mechanisms for tracking authentication credentials between
+requests, however they all interface with your application in mostly the same
+way.
-Above you learned about :ref:`assigning_acls`. Each :term:`principal` used
-in the :term:`ACL` is matched against the list returned from
+Above you learned about :ref:`assigning_acls`. Each :term:`principal` used in
+the :term:`ACL` is matched against the list returned from
:meth:`pyramid.interfaces.IAuthenticationPolicy.effective_principals`.
Similarly, :meth:`pyramid.request.Request.authenticated_userid` maps to
:meth:`pyramid.interfaces.IAuthenticationPolicy.authenticated_userid`.
You may control these values by subclassing the default authentication
policies. For example, below we subclass the
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and define
-extra functionality to query our database before confirming that the
-:term:`userid` is valid in order to avoid blindly trusting the value in the
-cookie (what if the cookie is still valid but the user has deleted their
-account?). We then use that :term:`userid` to augment the
-``effective_principals`` with information about groups and other state for
-that user.
+:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and define extra
+functionality to query our database before confirming that the :term:`userid`
+is valid in order to avoid blindly trusting the value in the cookie (what if
+the cookie is still valid, but the user has deleted their account?). We then
+use that :term:`userid` to augment the ``effective_principals`` with
+information about groups and other state for that user.
.. code-block:: python
:linenos:
@@ -630,8 +608,8 @@ that user.
return principals
In most instances ``authenticated_userid`` and ``effective_principals`` are
-application-specific whereas ``unauthenticated_userid``, ``remember`` and
-``forget`` are generic and focused on transport/serialization of data
+application-specific, whereas ``unauthenticated_userid``, ``remember``, and
+``forget`` are generic and focused on transport and serialization of data
between consecutive requests.
.. index::
@@ -642,12 +620,11 @@ between consecutive requests.
Creating Your Own Authentication Policy
---------------------------------------
-:app:`Pyramid` ships with a number of useful out-of-the-box
-security policies (see :mod:`pyramid.authentication`). However,
-creating your own authentication policy is often necessary when you
-want to control the "horizontal and vertical" of how your users
-authenticate. Doing so is a matter of creating an instance of something
-that implements the following interface:
+:app:`Pyramid` ships with a number of useful out-of-the-box security policies
+(see :mod:`pyramid.authentication`). However, creating your own authentication
+policy is often necessary when you want to control the "horizontal and
+vertical" of how your users authenticate. Doing so is a matter of creating an
+instance of something that implements the following interface:
.. code-block:: python
:linenos:
@@ -717,21 +694,19 @@ Creating Your Own Authorization Policy
--------------------------------------
An authorization policy is a policy that allows or denies access after a user
-has been authenticated. Most :app:`Pyramid` applications will use the
-default :class:`pyramid.authorization.ACLAuthorizationPolicy`.
-
-However, in some cases, it's useful to be able to use a different
-authorization policy than the default
-:class:`~pyramid.authorization.ACLAuthorizationPolicy`. For example, it
-might be desirable to construct an alternate authorization policy which
-allows the application to use an authorization mechanism that does not
-involve :term:`ACL` objects.
-
-:app:`Pyramid` ships with only a single default authorization
-policy, so you'll need to create your own if you'd like to use a
-different one. Creating and using your own authorization policy is a
-matter of creating an instance of an object that implements the
-following interface:
+has been authenticated. Most :app:`Pyramid` applications will use the default
+:class:`pyramid.authorization.ACLAuthorizationPolicy`.
+
+However, in some cases, it's useful to be able to use a different authorization
+policy than the default :class:`~pyramid.authorization.ACLAuthorizationPolicy`.
+For example, it might be desirable to construct an alternate authorization
+policy which allows the application to use an authorization mechanism that does
+not involve :term:`ACL` objects.
+
+:app:`Pyramid` ships with only a single default authorization policy, so you'll
+need to create your own if you'd like to use a different one. Creating and
+using your own authorization policy is a matter of creating an instance of an
+object that implements the following interface:
.. code-block:: python
:linenos:
@@ -782,4 +757,3 @@ which would allow the attacker to control the content of the payload. Re-using
a secret across two different subsystems might drop the security of signing to
zero. Keys should not be re-used across different contexts where an attacker
has the possibility of providing a chosen plaintext.
-
diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst
index 485f6b181..3e168eaea 100644
--- a/docs/narr/startup.rst
+++ b/docs/narr/startup.rst
@@ -6,15 +6,15 @@ Startup
When you cause a :app:`Pyramid` application to start up in a console window,
you'll see something much like this show up on the console:
-.. code-block:: text
+.. code-block:: bash
- $ pserve development.ini
- Starting server in PID 16601.
- serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
+ $ $VENV/bin/pserve development.ini
+ Starting server in PID 16305.
+ serving on http://127.0.0.1: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 0.0.0.0:6543 ...`` is output to your console.
+``serving on http://127.0.0.1:6543`` is output to your console.
.. index::
single: startup process
@@ -92,11 +92,11 @@ Here's a high-level time-ordered overview of what happens when you press
In this case, the ``myproject.__init__:main`` function referred to by the
entry point URI ``egg:MyProject`` (see :ref:`MyProject_ini` for more
information about entry point URIs, and how they relate to callables) will
- receive the key/value pairs ``{'pyramid.reload_templates':'true',
- 'pyramid.debug_authorization':'false', 'pyramid.debug_notfound':'false',
- 'pyramid.debug_routematch':'false', 'pyramid.debug_templates':'true',
- 'pyramid.default_locale_name':'en'}``. See :ref:`environment_chapter` for
- the meanings of these keys.
+ receive the key/value pairs ``{pyramid.reload_templates = true,
+ pyramid.debug_authorization = false, pyramid.debug_notfound = false,
+ pyramid.debug_routematch = false, pyramid.default_locale_name = en, and
+ pyramid.includes = pyramid_debugtoolbar}``. See :ref:`environment_chapter`
+ for the meanings of these keys.
#. The ``main`` function first constructs a
:class:`~pyramid.config.Configurator` instance, passing the ``settings``
@@ -131,10 +131,9 @@ Here's a high-level time-ordered overview of what happens when you press
#. ``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 (``host =
- 0.0.0.0``), on port number 6543 (``port = 6543``). The server code itself
- is what prints ``serving on 0.0.0.0:6543 view at http://127.0.0.1:6543``.
- The server serves the application, and the application is running, waiting
- to receive requests.
+ 127.0.0.1``), on port number 6543 (``port = 6543``). The server code itself
+ is what prints ``serving on http://127.0.0.1:6543``. The server serves the
+ application, and the application is running, waiting to receive requests.
.. seealso::
Logging configuration is described in the :ref:`logging_chapter` chapter.
diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst
index 4b4e99d41..02ae14aa5 100644
--- a/docs/narr/subrequest.rst
+++ b/docs/narr/subrequest.rst
@@ -17,6 +17,7 @@ application.
Here's an example application which uses a subrequest:
.. code-block:: python
+ :linenos:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -41,16 +42,16 @@ Here's an example application which uses a subrequest:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-When ``/view_one`` is visted in a browser, the text printed in the browser
-pane will be ``This came from view_two``. The ``view_one`` view used the
-:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response
-from another view (``view_two``) within the same application when it
-executed. It did so by constructing a new request that had a URL that it
-knew would match the ``view_two`` view registration, and passed that new
-request along to :meth:`pyramid.request.Request.invoke_subrequest`. The
-``view_two`` view callable was invoked, and it returned a response. The
-``view_one`` view callable then simply returned the response it obtained from
-the ``view_two`` view callable.
+When ``/view_one`` is visted in a browser, the text printed in the browser pane
+will be ``This came from view_two``. The ``view_one`` view used the
+:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response from
+another view (``view_two``) within the same application when it executed. It
+did so by constructing a new request that had a URL that it knew would match
+the ``view_two`` view registration, and passed that new request along to
+:meth:`pyramid.request.Request.invoke_subrequest`. The ``view_two`` view
+callable was invoked, and it returned a response. The ``view_one`` view
+callable then simply returned the response it obtained from the ``view_two``
+view callable.
Note that it doesn't matter if the view callable invoked via a subrequest
actually returns a *literal* Response object. Any view callable that uses a
@@ -60,6 +61,8 @@ adapter when found and invoked via
object:
.. code-block:: python
+ :linenos:
+ :emphasize-lines: 11
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -83,19 +86,19 @@ object:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-Even though the ``view_two`` view callable returned a string, it was invoked
-in such a way that the ``string`` renderer associated with the view
-registration that was found turned it into a "real" response object for
-consumption by ``view_one``.
+Even though the ``view_two`` view callable returned a string, it was invoked in
+such a way that the ``string`` renderer associated with the view registration
+that was found turned it into a "real" response object for consumption by
+``view_one``.
Being able to unconditionally obtain a response object by invoking a view
callable indirectly is the main advantage to using
-:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing
-a view callable and executing it directly. Note that there's not much
-advantage to invoking a view using a subrequest if you *can* invoke a view
-callable directly. Subrequests are slower and are less convenient if you
-actually do want just the literal information returned by a function that
-happens to be a view callable.
+:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing a
+view callable and executing it directly. Note that there's not much advantage
+to invoking a view using a subrequest if you *can* invoke a view callable
+directly. Subrequests are slower and are less convenient if you actually do
+want just the literal information returned by a function that happens to be a
+view callable.
Note that, by default, if a view callable invoked by a subrequest raises an
exception, the exception will be raised to the caller of
@@ -103,6 +106,8 @@ exception, the exception will be raised to the caller of
:term:`exception view` configured:
.. code-block:: python
+ :linenos:
+ :emphasize-lines: 11-16
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -136,15 +141,21 @@ When we run the above code and visit ``/view_one`` in a browser, the
``excview`` :term:`exception view` will *not* be executed. Instead, the call
to :meth:`~pyramid.request.Request.invoke_subrequest` will cause a
:exc:`ValueError` exception to be raised and a response will never be
-generated. We can change this behavior; how to do so is described below in
-our discussion of the ``use_tweens`` argument.
+generated. We can change this behavior; how to do so is described below in our
+discussion of the ``use_tweens`` argument.
+
+.. index::
+ pair: subrequest; use_tweens
+
+Subrequests with Tweens
+-----------------------
The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two
-arguments: a positional argument ``request`` that must be provided, and
-``use_tweens`` keyword argument that is optional; it defaults to ``False``.
+arguments: a required positional argument ``request``, and an optional keyword
+argument ``use_tweens`` which defaults to ``False``.
-The ``request`` object passed to the API must be an object that implements
-the Pyramid request interface (such as a :class:`pyramid.request.Request`
+The ``request`` object passed to the API must be an object that implements the
+Pyramid request interface (such as a :class:`pyramid.request.Request`
instance). If ``use_tweens`` is ``True``, the request will be sent to the
:term:`tween` in the tween stack closest to the request ingress. If
``use_tweens`` is ``False``, the request will be sent to the main router
@@ -153,9 +164,9 @@ handler, and no tweens will be invoked.
In the example above, the call to
:meth:`~pyramid.request.Request.invoke_subrequest` will always raise an
exception. This is because it's using the default value for ``use_tweens``,
-which is ``False``. You can pass ``use_tweens=True`` instead to ensure that
-it will convert an exception to a Response if an :term:`exception view` is
-configured instead of raising the exception. This is because exception views
+which is ``False``. Alternatively, you can pass ``use_tweens=True`` to ensure
+that it will convert an exception to a Response if an :term:`exception view` is
+configured, instead of raising the exception. This is because exception views
are called by the exception view :term:`tween` as described in
:ref:`exception_views` when any view raises an exception.
@@ -164,6 +175,8 @@ We can cause the subrequest to be run through the tween stack by passing
:meth:`~pyramid.request.Request.invoke_subrequest`, like this:
.. code-block:: python
+ :linenos:
+ :emphasize-lines: 7
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
@@ -199,71 +212,70 @@ attempted invocation of ``view_two``, because the tween which invokes an
exception view to generate a response is run, and therefore ``excview`` is
executed.
-This is one of the major differences between specifying the
-``use_tweens=True`` and ``use_tweens=False`` arguments to
+This is one of the major differences between specifying the ``use_tweens=True``
+and ``use_tweens=False`` arguments to
:meth:`~pyramid.request.Request.invoke_subrequest`. ``use_tweens=True`` may
-also imply invoking transaction commit/abort for the logic executed in the
-subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug
-HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other
+also imply invoking a transaction commit or abort for the logic executed in the
+subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug HTML
+if you've got ``pyramid_debugtoolbar`` in the tween list, and other
tween-related side effects as defined by your particular tween list.
The :meth:`~pyramid.request.Request.invoke_subrequest` function also
-unconditionally:
-
-- manages the threadlocal stack so that
+unconditionally does the following:
+
+- It manages the threadlocal stack so that
:func:`~pyramid.threadlocal.get_current_request` and
- :func:`~pyramid.threadlocal.get_current_registry` work during a request
- (they will return the subrequest instead of the original request)
+ :func:`~pyramid.threadlocal.get_current_registry` work during a request (they
+ will return the subrequest instead of the original request).
-- Adds a ``registry`` attribute and a ``invoke_subrequest`` attribute (a
- callable) to the request object it's handed.
+- It adds a ``registry`` attribute and an ``invoke_subrequest`` attribute (a
+ callable) to the request object to which it is handed.
-- sets request extensions (such as those added via
+- It sets request extensions (such as those added via
:meth:`~pyramid.config.Configurator.add_request_method` or
:meth:`~pyramid.config.Configurator.set_request_property`) on the subrequest
- object passed as ``request``
+ object passed as ``request``.
-- causes a :class:`~pyramid.events.NewRequest` event to be sent at the
+- It causes a :class:`~pyramid.events.NewRequest` event to be sent at the
beginning of request processing.
-- causes a :class:`~pyramid.events.ContextFound` event to be sent when a
+- It causes a :class:`~pyramid.events.ContextFound` event to be sent when a
context resource is found.
-- Ensures that the user implied by the request passed has the necessary
- authorization to invoke view callable before calling it.
+- It ensures that the user implied by the request passed in has the necessary
+ authorization to invoke the view callable before calling it.
-- Calls any :term:`response callback` functions defined within the subrequest's
- lifetime if a response is obtained from the Pyramid application.
+- It calls any :term:`response callback` functions defined within the
+ subrequest's lifetime if a response is obtained from the Pyramid application.
-- causes a :class:`~pyramid.events.NewResponse` event to be sent if a response
- is obtained.
+- It causes a :class:`~pyramid.events.NewResponse` event to be sent if a
+ response is obtained.
-- Calls any :term:`finished callback` functions defined within the subrequest's
- lifetime.
+- It calls any :term:`finished callback` functions defined within the
+ subrequest's lifetime.
-The invocation of a subrequest has more or less exactly the same effect as
-the invocation of a request received by the Pyramid router from a web client
+The invocation of a subrequest has more or less exactly the same effect as the
+invocation of a request received by the :app:`Pyramid` router from a web client
when ``use_tweens=True``. When ``use_tweens=False``, the tweens are skipped
but all the other steps take place.
It's a poor idea to use the original ``request`` object as an argument to
-:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a
-new request instead as demonstrated in the above example, using
+:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a new
+request instead as demonstrated in the above example, using
:meth:`pyramid.request.Request.blank`. Once you've constructed a request
-object, you'll need to massage it to match the view callable you'd like
-to be executed during the subrequest. This can be done by adjusting the
+object, you'll need to massage it to match the view callable that you'd like to
+be executed during the subrequest. This can be done by adjusting the
subrequest's URL, its headers, its request method, and other attributes. The
documentation for :class:`pyramid.request.Request` exposes the methods you
-should call and attributes you should set on the request you create to
-massage it into something that will actually match the view you'd like to
-call via a subrequest.
-
-We've demonstrated use of a subrequest from within a view callable, but you
-can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from
-within a tween or an event handler as well. It's usually a poor idea to
-invoke :meth:`~pyramid.request.Request.invoke_subrequest` from within a
-tween, because tweens already by definition have access to a function that
-will cause a subrequest (they are passed a ``handle`` function), but you can
-do it. It's fine to invoke
-:meth:`~pyramid.request.Request.invoke_subrequest` from within an event
-handler, however.
+should call and attributes you should set on the request that you create, then
+massage it into something that will actually match the view you'd like to call
+via a subrequest.
+
+We've demonstrated use of a subrequest from within a view callable, but you can
+use the :meth:`~pyramid.request.Request.invoke_subrequest` API from within a
+tween or an event handler as well. Even though you can do it, it's usually a
+poor idea to invoke :meth:`~pyramid.request.Request.invoke_subrequest` from
+within a tween, because tweens already, by definition, have access to a
+function that will cause a subrequest (they are passed a ``handle`` function).
+It's fine to invoke :meth:`~pyramid.request.Request.invoke_subrequest` from
+within an event handler, however.
diff --git a/docs/narr/tb_introspector.png b/docs/narr/tb_introspector.png
index 4ae406a86..b00d36067 100644
--- a/docs/narr/tb_introspector.png
+++ b/docs/narr/tb_introspector.png
Binary files differ
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index ecda57489..a3f62058b 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -13,34 +13,32 @@ application. In this context, a "unit" is often a function or a method of a
class instance. The unit is also referred to as a "unit under test".
The goal of a single unit test is to test **only** some permutation of the
-"unit under test". If you write a unit test that aims to verify the result
-of a particular codepath through a Python function, you need only be
-concerned about testing the code that *lives in the function body itself*.
-If the function accepts a parameter that represents a complex application
-"domain object" (such as a resource, a database connection, or an SMTP
-server), the argument provided to this function during a unit test *need not
-be* and likely *should not be* a "real" implementation object. For example,
-although a particular function implementation may accept an argument that
-represents an SMTP server object, and the function may call a method of this
-object when the system is operating normally that would result in an email
-being sent, a unit test of this codepath of the function does *not* need to
-test that an email is actually sent. It just needs to make sure that the
-function calls the method of the object provided as an argument that *would*
-send an email if the argument happened to be the "real" implementation of an
-SMTP server object.
+"unit under test". If you write a unit test that aims to verify the result of
+a particular codepath through a Python function, you need only be concerned
+about testing the code that *lives in the function body itself*. If the
+function accepts a parameter that represents a complex application "domain
+object" (such as a resource, a database connection, or an SMTP server), the
+argument provided to this function during a unit test *need not be* and likely
+*should not be* a "real" implementation object. For example, although a
+particular function implementation may accept an argument that represents an
+SMTP server object, and the function may call a method of this object when the
+system is operating normally that would result in an email being sent, a unit
+test of this codepath of the function does *not* need to test that an email is
+actually sent. It just needs to make sure that the function calls the method
+of the object provided as an argument that *would* send an email if the
+argument happened to be the "real" implementation of an SMTP server object.
An *integration test*, on the other hand, is a different form of testing in
which the interaction between two or more "units" is explicitly tested.
-Integration tests verify that the components of your application work
-together. You *might* make sure that an email was actually sent in an
-integration test.
+Integration tests verify that the components of your application work together.
+You *might* make sure that an email was actually sent in an integration test.
A *functional test* is a form of integration test in which the application is
-run "literally". You would *have to* make sure that an email was actually
-sent in a functional test, because it tests your code end to end.
+run "literally". You would *have to* make sure that an email was actually sent
+in a functional test, because it tests your code end to end.
-It is often considered best practice to write each type of tests for any
-given codebase. Unit testing often provides the opportunity to obtain better
+It is often considered best practice to write each type of tests for any given
+codebase. Unit testing often provides the opportunity to obtain better
"coverage": it's usually possible to supply a unit under test with arguments
and/or an environment which causes *all* of its potential codepaths to be
executed. This is usually not as easy to do with a set of integration or
@@ -55,9 +53,9 @@ integration tests. A good :mod:`unittest` tutorial is available within `Dive
Into Python <http://www.diveintopython.net/unit_testing/index.html>`_ by Mark
Pilgrim.
-:app:`Pyramid` provides a number of facilities that make unit, integration,
-and functional tests easier to write. The facilities become particularly
-useful when your code calls into :app:`Pyramid` -related framework functions.
+:app:`Pyramid` provides a number of facilities that make unit, integration, and
+functional tests easier to write. The facilities become particularly useful
+when your code calls into :app:`Pyramid`-related framework functions.
.. index::
single: test setup
@@ -67,42 +65,41 @@ useful when your code calls into :app:`Pyramid` -related framework functions.
.. _test_setup_and_teardown:
Test Set Up and Tear Down
---------------------------
+-------------------------
:app:`Pyramid` uses a "global" (actually :term:`thread local`) data structure
to hold two items: the current :term:`request` and the current
:term:`application registry`. These data structures are available via the
:func:`pyramid.threadlocal.get_current_request` and
-:func:`pyramid.threadlocal.get_current_registry` functions, respectively.
-See :ref:`threadlocals_chapter` for information about these functions and the
-data structures they return.
+:func:`pyramid.threadlocal.get_current_registry` functions, respectively. See
+:ref:`threadlocals_chapter` for information about these functions and the data
+structures they return.
If your code uses these ``get_current_*`` functions or calls :app:`Pyramid`
code which uses ``get_current_*`` functions, you will need to call
:func:`pyramid.testing.setUp` in your test setup and you will need to call
:func:`pyramid.testing.tearDown` in your test teardown.
-:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread
-local` stack, which makes the ``get_current_*`` functions work. It returns a
+:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread local`
+stack, which makes the ``get_current_*`` functions work. It returns a
:term:`Configurator` object which can be used to perform extra configuration
required by the code under test. :func:`~pyramid.testing.tearDown` pops the
thread local stack.
-Normally when a Configurator is used directly with the ``main`` block of
-a Pyramid application, it defers performing any "real work" until its
-``.commit`` method is called (often implicitly by the
-:meth:`pyramid.config.Configurator.make_wsgi_app` method). The
-Configurator returned by :func:`~pyramid.testing.setUp` is an
-*autocommitting* Configurator, however, which performs all actions
-implied by methods called on it immediately. This is more convenient
-for unit-testing purposes than needing to call
-:meth:`pyramid.config.Configurator.commit` in each test after adding
-extra configuration statements.
+Normally when a Configurator is used directly with the ``main`` block of a
+Pyramid application, it defers performing any "real work" until its ``.commit``
+method is called (often implicitly by the
+:meth:`pyramid.config.Configurator.make_wsgi_app` method). The Configurator
+returned by :func:`~pyramid.testing.setUp` is an *autocommitting* Configurator,
+however, which performs all actions implied by methods called on it
+immediately. This is more convenient for unit testing purposes than needing to
+call :meth:`pyramid.config.Configurator.commit` in each test after adding extra
+configuration statements.
The use of the :func:`~pyramid.testing.setUp` and
-:func:`~pyramid.testing.tearDown` functions allows you to supply each unit
-test method in a test case with an environment that has an isolated registry
-and an isolated request for the duration of a single test. Here's an example
-of using this feature:
+:func:`~pyramid.testing.tearDown` functions allows you to supply each unit test
+method in a test case with an environment that has an isolated registry and an
+isolated request for the duration of a single test. Here's an example of using
+this feature:
.. code-block:: python
:linenos:
@@ -117,22 +114,21 @@ of using this feature:
def tearDown(self):
testing.tearDown()
-The above will make sure that
-:func:`~pyramid.threadlocal.get_current_registry` called within a test
-case method of ``MyTest`` will return the :term:`application registry`
-associated with the ``config`` Configurator instance. Each test case
-method attached to ``MyTest`` will use an isolated registry.
+The above will make sure that :func:`~pyramid.threadlocal.get_current_registry`
+called within a test case method of ``MyTest`` will return the
+:term:`application registry` associated with the ``config`` Configurator
+instance. Each test case method attached to ``MyTest`` will use an isolated
+registry.
The :func:`~pyramid.testing.setUp` and :func:`~pyramid.testing.tearDown`
-functions accepts various arguments that influence the environment of the
-test. See the :ref:`testing_module` API for information about the extra
-arguments supported by these functions.
+functions accept various arguments that influence the environment of the test.
+See the :ref:`testing_module` API for information about the extra arguments
+supported by these functions.
If you also want to make :func:`~pyramid.threadlocal.get_current_request`
return something other than ``None`` during the course of a single test, you
-can pass a
-:term:`request` object into the :func:`pyramid.testing.setUp` within the
-``setUp`` method of your test:
+can pass a :term:`request` object into the :func:`pyramid.testing.setUp` within
+the ``setUp`` method of your test:
.. code-block:: python
:linenos:
@@ -148,24 +144,23 @@ can pass a
def tearDown(self):
testing.tearDown()
-If you pass a :term:`request` object into :func:`pyramid.testing.setUp`
-within your test case's ``setUp``, any test method attached to the
-``MyTest`` test case that directly or indirectly calls
+If you pass a :term:`request` object into :func:`pyramid.testing.setUp` within
+your test case's ``setUp``, any test method attached to the ``MyTest`` test
+case that directly or indirectly calls
:func:`~pyramid.threadlocal.get_current_request` will receive the request
object. Otherwise, during testing,
-:func:`~pyramid.threadlocal.get_current_request` will return ``None``.
-We use a "dummy" request implementation supplied by
-:class:`pyramid.testing.DummyRequest` because it's easier to construct
-than a "real" :app:`Pyramid` request object.
+:func:`~pyramid.threadlocal.get_current_request` will return ``None``. We use a
+"dummy" request implementation supplied by
+:class:`pyramid.testing.DummyRequest` because it's easier to construct than a
+"real" :app:`Pyramid` request object.
Test setup using a context manager
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-An alternative style of setting up a test configuration is to use the
-`with` statement and :func:`pyramid.testing.testConfig` to create a
-context manager. The context manager will call
-:func:`pyramid.testing.setUp` before the code under test and
-:func:`pyramid.testing.tearDown` afterwards.
+An alternative style of setting up a test configuration is to use the ``with``
+statement and :func:`pyramid.testing.testConfig` to create a context manager.
+The context manager will call :func:`pyramid.testing.setUp` before the code
+under test and :func:`pyramid.testing.tearDown` afterwards.
This style is useful for small self-contained tests. For example:
@@ -193,8 +188,8 @@ they're used by frameworks. Sorry. So here's a rule of thumb: if you don't
about any of this, but you still want to write test code, just always call
:func:`pyramid.testing.setUp` in your test's ``setUp`` method and
:func:`pyramid.testing.tearDown` in your tests' ``tearDown`` method. This
-won't really hurt anything if the application you're testing does not call
-any ``get_current*`` function.
+won't really hurt anything if the application you're testing does not call any
+``get_current*`` function.
.. index::
single: pyramid.testing
@@ -225,15 +220,15 @@ function.
.. note::
This code implies that you have defined a renderer imperatively in a
- relevant :class:`pyramid.config.Configurator` instance,
- otherwise it would fail when run normally.
+ relevant :class:`pyramid.config.Configurator` instance, otherwise it would
+ fail when run normally.
Without doing anything special during a unit test, the call to
:meth:`~pyramid.request.Request.has_permission` in this view function will
always return a ``True`` value. When a :app:`Pyramid` application starts
-normally, it will populate a :term:`application registry` using
+normally, it will populate an :term:`application registry` using
:term:`configuration declaration` calls made against a :term:`Configurator`.
-But if this application registry is not created and populated (e.g. by
+But if this application registry is not created and populated (e.g., by
initializing the configurator with an authorization policy), like when you
invoke application code via a unit test, :app:`Pyramid` API functions will tend
to either fail or return default results. So how do you test the branch of the
@@ -283,10 +278,10 @@ In the above example, we create a ``MyTest`` test case that inherits from
be found when ``setup.py test`` is run. It has two test methods.
The first test method, ``test_view_fn_forbidden`` tests the ``view_fn`` when
-the authentication policy forbids the current user the ``edit`` permission.
-Its third line registers a "dummy" "non-permissive" authorization policy
-using the :meth:`~pyramid.config.Configurator.testing_securitypolicy` method,
-which is a special helper method for unit testing.
+the authentication policy forbids the current user the ``edit`` permission. Its
+third line registers a "dummy" "non-permissive" authorization policy using the
+:meth:`~pyramid.config.Configurator.testing_securitypolicy` method, which is a
+special helper method for unit testing.
We then create a :class:`pyramid.testing.DummyRequest` object which simulates a
WebOb request object API. A :class:`pyramid.testing.DummyRequest` is a request
@@ -300,25 +295,25 @@ access. We check that the view function raises a
The second test method, named ``test_view_fn_allowed``, tests the alternate
case, where the authentication policy allows access. Notice that we pass
-different values to
-:meth:`~pyramid.config.Configurator.testing_securitypolicy` to obtain this
-result. We assert at the end of this that the view function returns a value.
+different values to :meth:`~pyramid.config.Configurator.testing_securitypolicy`
+to obtain this result. We assert at the end of this that the view function
+returns a value.
Note that the test calls the :func:`pyramid.testing.setUp` function in its
``setUp`` method and the :func:`pyramid.testing.tearDown` function in its
-``tearDown`` method. We assign the result of :func:`pyramid.testing.setUp`
-as ``config`` on the unittest class. This is a :term:`Configurator` object
-and all methods of the configurator can be called as necessary within
-tests. If you use any of the :class:`~pyramid.config.Configurator` APIs during
-testing, be sure to use this pattern in your test case's ``setUp`` and
-``tearDown``; these methods make sure you're using a "fresh"
-:term:`application registry` per test run.
-
-See the :ref:`testing_module` chapter for the entire :app:`Pyramid` -specific
+``tearDown`` method. We assign the result of :func:`pyramid.testing.setUp` as
+``config`` on the unittest class. This is a :term:`Configurator` object and
+all methods of the configurator can be called as necessary within tests. If you
+use any of the :class:`~pyramid.config.Configurator` APIs during testing, be
+sure to use this pattern in your test case's ``setUp`` and ``tearDown``; these
+methods make sure you're using a "fresh" :term:`application registry` per test
+run.
+
+See the :ref:`testing_module` chapter for the entire :app:`Pyramid`-specific
testing API. This chapter describes APIs for registering a security policy,
-registering resources at paths, registering event listeners, registering
-views and view permissions, and classes representing "dummy" implementations
-of a request and a resource.
+registering resources at paths, registering event listeners, registering views
+and view permissions, and classes representing "dummy" implementations of a
+request and a resource.
.. seealso::
@@ -353,26 +348,6 @@ code's integration with the rest of :app:`Pyramid`.
See also :ref:`including_configuration`
-Let's demonstrate this by showing an integration test for a view.
-
-Given the following view definition, which assumes that your application's
-:term:`package` name is ``myproject``, and within that :term:`package` there
-exists a module ``views``, which in turn contains a :term:`view` function named
-``my_view``:
-
- .. literalinclude:: MyProject/myproject/views.py
- :linenos:
- :lines: 1-6
- :language: python
-
-You'd then create a ``tests`` module within your ``myproject`` package,
-containing the following test code:
-
- .. literalinclude:: MyProject/myproject/tests.py
- :linenos:
- :pyobject: ViewIntegrationTests
- :language: python
-
Writing unit tests that use the :class:`~pyramid.config.Configurator` API to
set up the right "mock" registrations is often preferred to creating
integration tests. Unit tests will run faster (because they do less for each
@@ -392,24 +367,55 @@ In Pyramid, functional tests are typically written using the :term:`WebTest`
package, which provides APIs for invoking HTTP(S) requests to your application.
Regardless of which testing :term:`package` you use, ensure to add a
-``tests_require`` dependency on that package to to your application's
-``setup.py`` file:
+``tests_require`` dependency on that package to your application's
+``setup.py`` file. Using the project ``MyProject`` generated by the starter
+scaffold as described in :doc:`project`, we would insert the following code immediately following the
+``requires`` block in the file ``MyProject/setup.py``.
- .. literalinclude:: MyProject/setup.py
- :linenos:
- :emphasize-lines: 26-28,48
- :language: python
+.. code-block:: ini
+ :linenos:
+ :lineno-start: 11
+ :emphasize-lines: 8-
+
+ requires = [
+ 'pyramid',
+ 'pyramid_chameleon',
+ 'pyramid_debugtoolbar',
+ 'waitress',
+ ]
+
+ test_requires = [
+ 'webtest',
+ ]
+
+Remember to change the dependency.
+
+.. code-block:: ini
+ :linenos:
+ :lineno-start: 39
+ :emphasize-lines: 2
+
+ install_requires=requires,
+ tests_require=test_requires,
+ test_suite="myproject",
+
+As always, whenever you change your dependencies, make sure to run the
+following command.
+
+.. code-block:: bash
+
+ $VENV/bin/python setup.py develop
-Assuming your :term:`package` is named ``myproject``, which contains a
-``views`` module, which in turn contains a :term:`view` function ``my_view``
-that returns a HTML body when the root URL is invoked:
+In your ``MyPackage`` project, your :term:`package` is named ``myproject``
+which contains a ``views`` module, which in turn contains a :term:`view`
+function ``my_view`` that returns an HTML body when the root URL is invoked:
.. literalinclude:: MyProject/myproject/views.py
:linenos:
:language: python
-Then the following example functional test (shown below) demonstrates invoking
-the :term:`view` shown above:
+The following example functional test demonstrates invoking the above
+:term:`view`:
.. literalinclude:: MyProject/myproject/tests.py
:linenos:
@@ -419,9 +425,9 @@ the :term:`view` shown above:
When this test is run, each test method creates a "real" :term:`WSGI`
application using the ``main`` function in your ``myproject.__init__`` module,
using :term:`WebTest` to wrap that WSGI application. It assigns the result to
-``self.testapp``. In the test named ``test_root``. The ``TestApp``'s ``get``
+``self.testapp``. In the test named ``test_root``, the ``TestApp``'s ``GET``
method is used to invoke the root URL. Finally, an assertion is made that the
-returned HTML contains the text ``MyProject``.
+returned HTML contains the text ``Pyramid``.
-See the :term:`WebTest` documentation for further information about the
-methods available to a :class:`webtest.app.TestApp` instance.
+See the :term:`WebTest` documentation for further information about the methods
+available to a :class:`webtest.app.TestApp` instance.
diff --git a/docs/narr/threadlocals.rst b/docs/narr/threadlocals.rst
index afe56de3e..7437a3a76 100644
--- a/docs/narr/threadlocals.rst
+++ b/docs/narr/threadlocals.rst
@@ -8,26 +8,24 @@
Thread Locals
=============
-A :term:`thread local` variable is a variable that appears to be a
-"global" variable to an application which uses it. However, unlike a
-true global variable, one thread or process serving the application
-may receive a different value than another thread or process when that
-variable is "thread local".
+A :term:`thread local` variable is a variable that appears to be a "global"
+variable to an application which uses it. However, unlike a true global
+variable, one thread or process serving the application may receive a different
+value than another thread or process when that variable is "thread local".
-When a request is processed, :app:`Pyramid` makes two :term:`thread
-local` variables available to the application: a "registry" and a
-"request".
+When a request is processed, :app:`Pyramid` makes two :term:`thread local`
+variables available to the application: a "registry" and a "request".
Why and How :app:`Pyramid` Uses Thread Local Variables
----------------------------------------------------------
+------------------------------------------------------
-How are thread locals beneficial to :app:`Pyramid` and application
-developers who use :app:`Pyramid`? Well, usually they're decidedly
-**not**. Using a global or a thread local variable in any application
-usually makes it a lot harder to understand for a casual reader. Use
-of a thread local or a global is usually just a way to avoid passing
-some value around between functions, which is itself usually a very
-bad idea, at least if code readability counts as an important concern.
+How are thread locals beneficial to :app:`Pyramid` and application developers
+who use :app:`Pyramid`? Well, usually they're decidedly **not**. Using a
+global or a thread local variable in any application usually makes it a lot
+harder to understand for a casual reader. Use of a thread local or a global is
+usually just a way to avoid passing some value around between functions, which
+is itself usually a very bad idea, at least if code readability counts as an
+important concern.
For historical reasons, however, thread local variables are indeed consulted by
various :app:`Pyramid` API functions. For example, the implementation of the
@@ -40,119 +38,107 @@ application registry, from which it looks up the authentication policy; it then
uses the authentication policy to retrieve the authenticated user id. This is
how :app:`Pyramid` allows arbitrary authentication policies to be "plugged in".
-When they need to do so, :app:`Pyramid` internals use two API
-functions to retrieve the :term:`request` and :term:`application
-registry`: :func:`~pyramid.threadlocal.get_current_request` and
-:func:`~pyramid.threadlocal.get_current_registry`. The former
-returns the "current" request; the latter returns the "current"
-registry. Both ``get_current_*`` functions retrieve an object from a
-thread-local data structure. These API functions are documented in
-:ref:`threadlocal_module`.
-
-These values are thread locals rather than true globals because one
-Python process may be handling multiple simultaneous requests or even
-multiple :app:`Pyramid` applications. If they were true globals,
-:app:`Pyramid` could not handle multiple simultaneous requests or
-allow more than one :app:`Pyramid` application instance to exist in
-a single Python process.
-
-Because one :app:`Pyramid` application is permitted to call
-*another* :app:`Pyramid` application from its own :term:`view` code
-(perhaps as a :term:`WSGI` app with help from the
-:func:`pyramid.wsgi.wsgiapp2` decorator), these variables are
-managed in a *stack* during normal system operations. The stack
-instance itself is a :class:`threading.local`.
+When they need to do so, :app:`Pyramid` internals use two API functions to
+retrieve the :term:`request` and :term:`application registry`:
+:func:`~pyramid.threadlocal.get_current_request` and
+:func:`~pyramid.threadlocal.get_current_registry`. The former returns the
+"current" request; the latter returns the "current" registry. Both
+``get_current_*`` functions retrieve an object from a thread-local data
+structure. These API functions are documented in :ref:`threadlocal_module`.
+
+These values are thread locals rather than true globals because one Python
+process may be handling multiple simultaneous requests or even multiple
+:app:`Pyramid` applications. If they were true globals, :app:`Pyramid` could
+not handle multiple simultaneous requests or allow more than one :app:`Pyramid`
+application instance to exist in a single Python process.
+
+Because one :app:`Pyramid` application is permitted to call *another*
+:app:`Pyramid` application from its own :term:`view` code (perhaps as a
+:term:`WSGI` app with help from the :func:`pyramid.wsgi.wsgiapp2` decorator),
+these variables are managed in a *stack* during normal system operations. The
+stack instance itself is a :class:`threading.local`.
During normal operations, the thread locals stack is managed by a
-:term:`Router` object. At the beginning of a request, the Router
-pushes the application's registry and the request on to the stack. At
-the end of a request, the stack is popped. The topmost request and
-registry on the stack are considered "current". Therefore, when the
-system is operating normally, the very definition of "current" is
-defined entirely by the behavior of a pyramid :term:`Router`.
+:term:`Router` object. At the beginning of a request, the Router pushes the
+application's registry and the request on to the stack. At the end of a
+request, the stack is popped. The topmost request and registry on the stack
+are considered "current". Therefore, when the system is operating normally,
+the very definition of "current" is defined entirely by the behavior of a
+pyramid :term:`Router`.
However, during unit testing, no Router code is ever invoked, and the
-definition of "current" is defined by the boundary between calls to
-the :meth:`pyramid.config.Configurator.begin` and
-:meth:`pyramid.config.Configurator.end` methods (or between
-calls to the :func:`pyramid.testing.setUp` and
-:func:`pyramid.testing.tearDown` functions). These functions push
-and pop the threadlocal stack when the system is under test. See
-:ref:`test_setup_and_teardown` for the definitions of these functions.
-
-Scripts which use :app:`Pyramid` machinery but never actually start
-a WSGI server or receive requests via HTTP such as scripts which use
-the :mod:`pyramid.scripting` API will never cause any Router code
-to be executed. However, the :mod:`pyramid.scripting` APIs also
-push some values on to the thread locals stack as a matter of course.
-Such scripts should expect the
-:func:`~pyramid.threadlocal.get_current_request` function to always
-return ``None``, and should expect the
-:func:`~pyramid.threadlocal.get_current_registry` function to return
-exactly the same :term:`application registry` for every request.
+definition of "current" is defined by the boundary between calls to the
+:meth:`pyramid.config.Configurator.begin` and
+:meth:`pyramid.config.Configurator.end` methods (or between calls to the
+:func:`pyramid.testing.setUp` and :func:`pyramid.testing.tearDown` functions).
+These functions push and pop the threadlocal stack when the system is under
+test. See :ref:`test_setup_and_teardown` for the definitions of these
+functions.
+
+Scripts which use :app:`Pyramid` machinery but never actually start a WSGI
+server or receive requests via HTTP, such as scripts which use the
+:mod:`pyramid.scripting` API, will never cause any Router code to be executed.
+However, the :mod:`pyramid.scripting` APIs also push some values on to the
+thread locals stack as a matter of course. Such scripts should expect the
+:func:`~pyramid.threadlocal.get_current_request` function to always return
+``None``, and should expect the
+:func:`~pyramid.threadlocal.get_current_registry` function to return exactly
+the same :term:`application registry` for every request.
Why You Shouldn't Abuse Thread Locals
-------------------------------------
You probably should almost never use the
:func:`~pyramid.threadlocal.get_current_request` or
-:func:`~pyramid.threadlocal.get_current_registry` functions, except
-perhaps in tests. In particular, it's almost always a mistake to use
-``get_current_request`` or ``get_current_registry`` in application
-code because its usage makes it possible to write code that can be
-neither easily tested nor scripted. Inappropriate usage is defined as
-follows:
+:func:`~pyramid.threadlocal.get_current_registry` functions, except perhaps in
+tests. In particular, it's almost always a mistake to use
+``get_current_request`` or ``get_current_registry`` in application code because
+its usage makes it possible to write code that can be neither easily tested nor
+scripted. Inappropriate usage is defined as follows:
- ``get_current_request`` should never be called within the body of a
- :term:`view callable`, or within code called by a view callable.
- View callables already have access to the request (it's passed in to
- each as ``request``).
-
-- ``get_current_request`` should never be called in :term:`resource` code.
- If a resource needs access to the request, it should be passed the request
- by a :term:`view callable`.
-
-- ``get_current_request`` function should never be called because it's
- "easier" or "more elegant" to think about calling it than to pass a
- request through a series of function calls when creating some API
- design. Your application should instead almost certainly pass data
- derived from the request around rather than relying on being able to
- call this function to obtain the request in places that actually
- have no business knowing about it. Parameters are *meant* to be
- passed around as function arguments, this is why they exist. Don't
- try to "save typing" or create "nicer APIs" by using this function
- in the place where a request is required; this will only lead to
- sadness later.
-
-- Neither ``get_current_request`` nor ``get_current_registry`` should
- ever be called within application-specific forks of third-party
- library code. The library you've forked almost certainly has
- nothing to do with :app:`Pyramid`, and making it dependent on
- :app:`Pyramid` (rather than making your :app:`pyramid`
- application depend upon it) means you're forming a dependency in the
- wrong direction.
-
-Use of the :func:`~pyramid.threadlocal.get_current_request` function
-in application code *is* still useful in very limited circumstances.
-As a rule of thumb, usage of ``get_current_request`` is useful
-**within code which is meant to eventually be removed**. For
-instance, you may find yourself wanting to deprecate some API that
-expects to be passed a request object in favor of one that does not
-expect to be passed a request object. But you need to keep
-implementations of the old API working for some period of time while
-you deprecate the older API. So you write a "facade" implementation
-of the new API which calls into the code which implements the older
-API. Since the new API does not require the request, your facade
-implementation doesn't have local access to the request when it needs
-to pass it into the older API implementation. After some period of
-time, the older implementation code is disused and the hack that uses
-``get_current_request`` is removed. This would be an appropriate
-place to use the ``get_current_request``.
-
-Use of the :func:`~pyramid.threadlocal.get_current_registry`
-function should be limited to testing scenarios. The registry made
-current by use of the
-:meth:`pyramid.config.Configurator.begin` method during a
-test (or via :func:`pyramid.testing.setUp`) when you do not pass
-one in is available to you via this API.
-
+ :term:`view callable`, or within code called by a view callable. View
+ callables already have access to the request (it's passed in to each as
+ ``request``).
+
+- ``get_current_request`` should never be called in :term:`resource` code. If a
+ resource needs access to the request, it should be passed the request by a
+ :term:`view callable`.
+
+- ``get_current_request`` function should never be called because it's "easier"
+ or "more elegant" to think about calling it than to pass a request through a
+ series of function calls when creating some API design. Your application
+ should instead, almost certainly, pass around data derived from the request
+ rather than relying on being able to call this function to obtain the request
+ in places that actually have no business knowing about it. Parameters are
+ *meant* to be passed around as function arguments; this is why they exist.
+ Don't try to "save typing" or create "nicer APIs" by using this function in
+ the place where a request is required; this will only lead to sadness later.
+
+- Neither ``get_current_request`` nor ``get_current_registry`` should ever be
+ called within application-specific forks of third-party library code. The
+ library you've forked almost certainly has nothing to do with :app:`Pyramid`,
+ and making it dependent on :app:`Pyramid` (rather than making your
+ :app:`pyramid` application depend upon it) means you're forming a dependency
+ in the wrong direction.
+
+Use of the :func:`~pyramid.threadlocal.get_current_request` function in
+application code *is* still useful in very limited circumstances. As a rule of
+thumb, usage of ``get_current_request`` is useful **within code which is meant
+to eventually be removed**. For instance, you may find yourself wanting to
+deprecate some API that expects to be passed a request object in favor of one
+that does not expect to be passed a request object. But you need to keep
+implementations of the old API working for some period of time while you
+deprecate the older API. So you write a "facade" implementation of the new API
+which calls into the code which implements the older API. Since the new API
+does not require the request, your facade implementation doesn't have local
+access to the request when it needs to pass it into the older API
+implementation. After some period of time, the older implementation code is
+disused and the hack that uses ``get_current_request`` is removed. This would
+be an appropriate place to use the ``get_current_request``.
+
+Use of the :func:`~pyramid.threadlocal.get_current_registry` function should be
+limited to testing scenarios. The registry made current by use of the
+:meth:`pyramid.config.Configurator.begin` method during a test (or via
+:func:`pyramid.testing.setUp`) when you do not pass one in is available to you
+via this API.
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index 454bb5620..cd8395eac 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -3,32 +3,30 @@
Traversal
=========
-This chapter explains the technical details of how traversal works in
-Pyramid.
+This chapter explains the technical details of how traversal works in Pyramid.
For a quick example, see :doc:`hellotraversal`.
For more about *why* you might use traversal, see :doc:`muchadoabouttraversal`.
A :term:`traversal` uses the URL (Universal Resource Locator) to find a
-:term:`resource` located in a :term:`resource tree`, which is a set of
-nested dictionary-like objects. Traversal is done by using each segment
-of the path portion of the URL to navigate through the :term:`resource
-tree`. You might think of this as looking up files and directories in a
-file system. Traversal walks down the path until it finds a published
-resource, analogous to a file system "directory" or "file". The
-resource found as the result of a traversal becomes the
-:term:`context` of the :term:`request`. Then, the :term:`view lookup`
-subsystem is used to find some view code willing to "publish" this
+:term:`resource` located in a :term:`resource tree`, which is a set of nested
+dictionary-like objects. Traversal is done by using each segment of the path
+portion of the URL to navigate through the :term:`resource tree`. You might
+think of this as looking up files and directories in a file system. Traversal
+walks down the path until it finds a published resource, analogous to a file
+system "directory" or "file". The resource found as the result of a traversal
+becomes the :term:`context` of the :term:`request`. Then, the :term:`view
+lookup` subsystem is used to find some view code willing to "publish" this
resource by generating a :term:`response`.
.. note::
Using :term:`Traversal` to map a URL to code is optional. If you're creating
- your first Pyramid application it probably makes more sense to use :term:`URL
- dispatch` to map URLs to code instead of traversal, as new Pyramid developers
- tend to find URL dispatch slightly easier to understand. If you use URL
- dispatch, you needn't read this chapter.
+ your first Pyramid application, it probably makes more sense to use
+ :term:`URL dispatch` to map URLs to code instead of traversal, as new Pyramid
+ developers tend to find URL dispatch slightly easier to understand. If you
+ use URL dispatch, you needn't read this chapter.
.. index::
single: traversal details
@@ -36,33 +34,32 @@ resource by generating a :term:`response`.
Traversal Details
-----------------
-:term:`Traversal` is dependent on information in a :term:`request`
-object. Every :term:`request` object contains URL path information in
-the ``PATH_INFO`` portion of the :term:`WSGI` environment. The
-``PATH_INFO`` string is the portion of a request's URL following the
-hostname and port number, but before any query string elements or
-fragment element. For example the ``PATH_INFO`` portion of the URL
-``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``.
+:term:`Traversal` is dependent on information in a :term:`request` object.
+Every :term:`request` object contains URL path information in the ``PATH_INFO``
+portion of the :term:`WSGI` environment. The ``PATH_INFO`` string is the
+portion of a request's URL following the hostname and port number, but before
+any query string elements or fragment element. For example the ``PATH_INFO``
+portion of the URL ``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``.
-Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of
-path segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is
-converted to the sequence ``['a', 'b', 'c']``.
+Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of path
+segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is converted to the
+sequence ``['a', 'b', 'c']``.
-This path sequence is then used to descend through the :term:`resource
-tree`, looking up a resource for each path segment. Each lookup uses the
+This path sequence is then used to descend through the :term:`resource tree`,
+looking up a resource for each path segment. Each lookup uses the
``__getitem__`` method of a resource in the tree.
For example, if the path info sequence is ``['a', 'b', 'c']``:
- :term:`Traversal` starts by acquiring the :term:`root` resource of the
- application by calling the :term:`root factory`. The :term:`root factory`
- can be configured to return whatever object is appropriate as the
- traversal root of your application.
+ application by calling the :term:`root factory`. The :term:`root factory` can
+ be configured to return whatever object is appropriate as the traversal root
+ of your application.
-- Next, the first element (``'a'``) is popped from the path segment
- sequence and is used as a key to lookup the corresponding resource
- in the root. This invokes the root resource's ``__getitem__`` method
- using that value (``'a'``) as an argument.
+- Next, the first element (``'a'``) is popped from the path segment sequence
+ and is used as a key to lookup the corresponding resource in the root. This
+ invokes the root resource's ``__getitem__`` method using that value (``'a'``)
+ as an argument.
- If the root resource "contains" a resource with key ``'a'``, its
``__getitem__`` method will return it. The :term:`context` temporarily
@@ -72,29 +69,26 @@ For example, if the path info sequence is ``['a', 'b', 'c']``:
resource's ``__getitem__`` is called with that value (``'b'``) as an
argument; we'll presume it succeeds.
-- The "A" resource's ``__getitem__`` returns another resource, which
- we'll call "B". The :term:`context` temporarily becomes the "B"
- resource.
+- The "A" resource's ``__getitem__`` returns another resource, which we'll call
+ "B". The :term:`context` temporarily becomes the "B" resource.
-Traversal continues until the path segment sequence is exhausted or a
-path element cannot be resolved to a resource. In either case, the
-:term:`context` resource is the last object that the traversal
-successfully resolved. If any resource found during traversal lacks a
-``__getitem__`` method, or if its ``__getitem__`` method raises a
-:exc:`KeyError`, traversal ends immediately, and that resource becomes
-the :term:`context`.
+Traversal continues until the path segment sequence is exhausted or a path
+element cannot be resolved to a resource. In either case, the :term:`context`
+resource is the last object that the traversal successfully resolved. If any
+resource found during traversal lacks a ``__getitem__`` method, or if its
+``__getitem__`` method raises a :exc:`KeyError`, traversal ends immediately,
+and that resource becomes the :term:`context`.
The results of a :term:`traversal` also include a :term:`view name`. If
-traversal ends before the path segment sequence is exhausted, the
-:term:`view name` is the *next* remaining path segment element. If the
-:term:`traversal` expends all of the path segments, then the :term:`view
-name` is the empty string (``''``).
+traversal ends before the path segment sequence is exhausted, the :term:`view
+name` is the *next* remaining path segment element. If the :term:`traversal`
+expends all of the path segments, then the :term:`view name` is the empty
+string (``''``).
-The combination of the context resource and the :term:`view name` found
-via traversal is used later in the same request by the :term:`view
-lookup` subsystem to find a :term:`view callable`. How :app:`Pyramid`
-performs view lookup is explained within the :ref:`view_config_chapter`
-chapter.
+The combination of the context resource and the :term:`view name` found via
+traversal is used later in the same request by the :term:`view lookup`
+subsystem to find a :term:`view callable`. How :app:`Pyramid` performs view
+lookup is explained within the :ref:`view_config_chapter` chapter.
.. index::
single: object tree
@@ -106,20 +100,20 @@ chapter.
The Resource Tree
-----------------
-The resource tree is a set of nested dictionary-like resource objects
-that begins with a :term:`root` resource. In order to use
-:term:`traversal` to resolve URLs to code, your application must supply
-a :term:`resource tree` to :app:`Pyramid`.
+The resource tree is a set of nested dictionary-like resource objects that
+begins with a :term:`root` resource. In order to use :term:`traversal` to
+resolve URLs to code, your application must supply a :term:`resource tree` to
+:app:`Pyramid`.
In order to supply a root resource for an application the :app:`Pyramid`
-:term:`Router` is configured with a callback known as a :term:`root
-factory`. The root factory is supplied by the application, at startup
-time, as the ``root_factory`` argument to the :term:`Configurator`.
+:term:`Router` is configured with a callback known as a :term:`root factory`.
+The root factory is supplied by the application at startup time as the
+``root_factory`` argument to the :term:`Configurator`.
-The root factory is a Python callable that accepts a :term:`request`
-object, and returns the root object of the :term:`resource tree`. A
-function, or class is typically used as an application's root factory.
-Here's an example of a simple root factory class:
+The root factory is a Python callable that accepts a :term:`request` object,
+and returns the root object of the :term:`resource tree`. A function or class
+is typically used as an application's root factory. Here's an example of a
+simple root factory class:
.. code-block:: python
:linenos:
@@ -136,62 +130,60 @@ passing it to an instance of a :term:`Configurator` named ``config``:
config = Configurator(root_factory=Root)
-The ``root_factory`` argument to the
-:class:`~pyramid.config.Configurator` constructor registers this root
-factory to be called to generate a root resource whenever a request
-enters the application. The root factory registered this way is also
-known as the global root factory. A root factory can alternately be
-passed to the ``Configurator`` as a :term:`dotted Python name` which can
-refer to a root factory defined in a different module.
+The ``root_factory`` argument to the :class:`~pyramid.config.Configurator`
+constructor registers this root factory to be called to generate a root
+resource whenever a request enters the application. The root factory
+registered this way is also known as the global root factory. A root factory
+can alternatively be passed to the ``Configurator`` as a :term:`dotted Python
+name` which can refer to a root factory defined in a different module.
-If no :term:`root factory` is passed to the :app:`Pyramid`
-:term:`Configurator` constructor, or if the ``root_factory`` value
-specified is ``None``, a :term:`default root factory` is used. The default
-root factory always returns a resource that has no child resources; it
-is effectively empty.
+If no :term:`root factory` is passed to the :app:`Pyramid` :term:`Configurator`
+constructor, or if the ``root_factory`` value specified is ``None``, a
+:term:`default root factory` is used. The default root factory always returns
+a resource that has no child resources; it is effectively empty.
Usually a root factory for a traversal-based application will be more
-complicated than the above ``Root`` class; in particular it may be associated
+complicated than the above ``Root`` class. In particular it may be associated
with a database connection or another persistence mechanism. The above
``Root`` class is analogous to the default root factory present in Pyramid. The
default root factory is very simple and not very useful.
.. note::
- If the items contained within the resource tree are "persistent" (they
- have state that lasts longer than the execution of a single process), they
- become analogous to the concept of :term:`domain model` objects used by
- many other frameworks.
+ If the items contained within the resource tree are "persistent" (they have
+ state that lasts longer than the execution of a single process), they become
+ analogous to the concept of :term:`domain model` objects used by many other
+ frameworks.
-The resource tree consists of *container* resources and *leaf* resources.
-There is only one difference between a *container* resource and a *leaf*
-resource: *container* resources possess a ``__getitem__`` method (making it
+The resource tree consists of *container* resources and *leaf* resources. There
+is only one difference between a *container* resource and a *leaf* resource:
+*container* resources possess a ``__getitem__`` method (making it
"dictionary-like") while *leaf* resources do not. The ``__getitem__`` method
was chosen as the signifying difference between the two types of resources
because the presence of this method is how Python itself typically determines
whether an object is "containerish" or not (dictionary objects are
"containerish").
-Each container resource is presumed to be willing to return a child resource
-or raise a ``KeyError`` based on a name passed to its ``__getitem__``.
+Each container resource is presumed to be willing to return a child resource or
+raise a ``KeyError`` based on a name passed to its ``__getitem__``.
-Leaf-level instances must not have a ``__getitem__``. If instances that
-you'd like to be leaves already happen to have a ``__getitem__`` through some
+Leaf-level instances must not have a ``__getitem__``. If instances that you'd
+like to be leaves already happen to have a ``__getitem__`` through some
historical inequity, you should subclass these resource types and cause their
``__getitem__`` methods to simply raise a ``KeyError``. Or just disuse them
and think up another strategy.
-Usually, the traversal root is a *container* resource, and as such it
-contains other resources. However, it doesn't *need* to be a container.
-Your resource tree can be as shallow or as deep as you require.
+Usually the traversal root is a *container* resource, and as such it contains
+other resources. However, it doesn't *need* to be a container. Your resource
+tree can be as shallow or as deep as you require.
-In general, the resource tree is traversed beginning at its root resource
-using a sequence of path elements described by the ``PATH_INFO`` of the
-current request; if there are path segments, the root resource's
-``__getitem__`` is called with the next path segment, and it is expected to
-return another resource. The resulting resource's ``__getitem__`` is called
-with the very next path segment, and it is expected to return another
-resource. This happens *ad infinitum* until all path segments are exhausted.
+In general, the resource tree is traversed beginning at its root resource using
+a sequence of path elements described by the ``PATH_INFO`` of the current
+request. If there are path segments, the root resource's ``__getitem__`` is
+called with the next path segment, and it is expected to return another
+resource. The resulting resource's ``__getitem__`` is called with the very
+next path segment, and it is expected to return another resource. This happens
+*ad infinitum* until all path segments are exhausted.
.. index::
single: traversal algorithm
@@ -204,17 +196,17 @@ The Traversal Algorithm
This section will attempt to explain the :app:`Pyramid` traversal algorithm.
We'll provide a description of the algorithm, a diagram of how the algorithm
-works, and some example traversal scenarios that might help you understand
-how the algorithm operates against a specific resource tree.
+works, and some example traversal scenarios that might help you understand how
+the algorithm operates against a specific resource tree.
We'll also talk a bit about :term:`view lookup`. The
-:ref:`view_config_chapter` chapter discusses :term:`view lookup` in
-detail, and it is the canonical source for information about views.
-Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that is
-separated from traversal entirely. However, we'll describe the
-fundamental behavior of view lookup in the examples in the next few
-sections to give you an idea of how traversal and view lookup cooperate,
-because they are almost always used together.
+:ref:`view_config_chapter` chapter discusses :term:`view lookup` in detail, and
+it is the canonical source for information about views. Technically,
+:term:`view lookup` is a :app:`Pyramid` subsystem that is separated from
+traversal entirely. However, we'll describe the fundamental behavior of view
+lookup in the examples in the next few sections to give you an idea of how
+traversal and view lookup cooperate, because they are almost always used
+together.
.. index::
single: view name
@@ -223,26 +215,24 @@ because they are almost always used together.
single: root factory
single: default view
-A Description of The Traversal Algorithm
+A Description of the Traversal Algorithm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When a user requests a page from your traversal-powered application, the
-system uses this algorithm to find a :term:`context` resource and a
-:term:`view name`.
+When a user requests a page from your traversal-powered application, the system
+uses this algorithm to find a :term:`context` resource and a :term:`view name`.
-#. The request for the page is presented to the :app:`Pyramid`
- :term:`router` in terms of a standard :term:`WSGI` request, which is
- represented by a WSGI environment and a WSGI ``start_response`` callable.
+#. The request for the page is presented to the :app:`Pyramid` :term:`router`
+ in terms of a standard :term:`WSGI` request, which is represented by a WSGI
+ environment and a WSGI ``start_response`` callable.
-#. The router creates a :term:`request` object based on the WSGI
- environment.
+#. The router creates a :term:`request` object based on the WSGI environment.
-#. The :term:`root factory` is called with the :term:`request`. It returns
- a :term:`root` resource.
+#. The :term:`root factory` is called with the :term:`request`. It returns a
+ :term:`root` resource.
#. The router uses the WSGI environment's ``PATH_INFO`` information to
- determine the path segments to traverse. The leading slash is stripped
- off ``PATH_INFO``, and the remaining path segments are split on the slash
+ determine the path segments to traverse. The leading slash is stripped off
+ ``PATH_INFO``, and the remaining path segments are split on the slash
character to form a traversal sequence.
The traversal algorithm by default attempts to first URL-unquote and then
@@ -252,26 +242,26 @@ system uses this algorithm to find a :term:`context` resource and a
Conversion from a URL-decoded string into Unicode is attempted using the
UTF-8 encoding. If any URL-unquoted path segment in ``PATH_INFO`` is not
decodeable using the UTF-8 decoding, a :exc:`TypeError` is raised. A
- segment will be fully URL-unquoted and UTF8-decoded before it is passed
- in to the ``__getitem__`` of any resource during traversal.
+ segment will be fully URL-unquoted and UTF8-decoded before it is passed in
+ to the ``__getitem__`` of any resource during traversal.
- Thus, a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
+ Thus a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
traversal sequence ``[u'a', u'b', u'c']``.
-#. :term:`Traversal` begins at the root resource returned by the root
- factory. For the traversal sequence ``[u'a', u'b', u'c']``, the root
- resource's ``__getitem__`` is called with the name ``'a'``. Traversal
- continues through the sequence. In our example, if the root resource's
- ``__getitem__`` called with the name ``a`` returns a resource (aka
+#. :term:`Traversal` begins at the root resource returned by the root factory.
+ For the traversal sequence ``[u'a', u'b', u'c']``, the root resource's
+ ``__getitem__`` is called with the name ``'a'``. Traversal continues
+ through the sequence. In our example, if the root resource's
+ ``__getitem__`` called with the name ``a`` returns a resource (a.k.a.
resource "A"), that resource's ``__getitem__`` is called with the name
``'b'``. If resource "A" returns a resource "B" when asked for ``'b'``,
resource B's ``__getitem__`` is then asked for the name ``'c'``, and may
return resource "C".
-#. Traversal ends when a) the entire path is exhausted or b) when any
- resource raises a :exc:`KeyError` from its ``__getitem__`` or c) when any
+#. Traversal ends when either (a) the entire path is exhausted, (b) when any
+ resource raises a :exc:`KeyError` from its ``__getitem__``, (c) when any
non-final path element traversal does not have a ``__getitem__`` method
- (resulting in a :exc:`AttributeError`) or d) when any path element is
+ (resulting in an :exc:`AttributeError`), or (d) when any path element is
prefixed with the set of characters ``@@`` (indicating that the characters
following the ``@@`` token should be treated as a :term:`view name`).
@@ -279,13 +269,13 @@ system uses this algorithm to find a :term:`context` resource and a
resource found during traversal is deemed to be the :term:`context`. If
the path has been exhausted when traversal ends, the :term:`view name` is
deemed to be the empty string (``''``). However, if the path was *not*
- exhausted before traversal terminated, the first remaining path segment
- is treated as the view name.
+ exhausted before traversal terminated, the first remaining path segment is
+ treated as the view name.
#. Any subsequent path elements after the :term:`view name` is found are
deemed the :term:`subpath`. The subpath is always a sequence of path
- segments that come from ``PATH_INFO`` that are "left over" after
- traversal has completed.
+ segments that come from ``PATH_INFO`` that are "left over" after traversal
+ has completed.
Once the :term:`context` resource, the :term:`view name`, and associated
attributes such as the :term:`subpath` are located, the job of
@@ -297,20 +287,19 @@ The traversal algorithm exposes two special cases:
- You will often end up with a :term:`view name` that is the empty string as
the result of a particular traversal. This indicates that the view lookup
- machinery should look up the :term:`default view`. The default view is a
- view that is registered with no name or a view which is registered with a
- name that equals the empty string.
+ machinery should lookup the :term:`default view`. The default view is a view
+ that is registered with no name or a view which is registered with a name
+ that equals the empty string.
-- If any path segment element begins with the special characters ``@@``
- (think of them as goggles), the value of that segment minus the goggle
- characters is considered the :term:`view name` immediately and traversal
- stops there. This allows you to address views that may have the same names
- as resource names in the tree unambiguously.
+- If any path segment element begins with the special characters ``@@`` (think
+ of them as goggles), the value of that segment minus the goggle characters is
+ considered the :term:`view name` immediately and traversal stops there. This
+ allows you to address views that may have the same names as resource names in
+ the tree unambiguously.
Finally, traversal is responsible for locating a :term:`virtual root`. A
-virtual root is used during "virtual hosting"; see the
-:ref:`vhosting_chapter` chapter for information. We won't speak more about
-it in this chapter.
+virtual root is used during "virtual hosting". See the :ref:`vhosting_chapter`
+chapter for information. We won't speak more about it in this chapter.
.. image:: resourcetreetraverser.png
@@ -321,13 +310,13 @@ Traversal Algorithm Examples
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
No one can be expected to understand the traversal algorithm by analogy and
-description alone, so let's examine some traversal scenarios that use
-concrete URLs and resource tree compositions.
+description alone, so let's examine some traversal scenarios that use concrete
+URLs and resource tree compositions.
-Let's pretend the user asks for
-``http://example.com/foo/bar/baz/biz/buz.txt``. The request's ``PATH_INFO``
-in that case is ``/foo/bar/baz/biz/buz.txt``. Let's further pretend that
-when this request comes in that we're traversing the following resource tree:
+Let's pretend the user asks for ``http://example.com/foo/bar/baz/biz/buz.txt``.
+The request's ``PATH_INFO`` in that case is ``/foo/bar/baz/biz/buz.txt``.
+Let's further pretend that when this request comes in, we're traversing the
+following resource tree:
.. code-block:: text
@@ -346,33 +335,32 @@ Here's what happens:
finds.
- :term:`traversal` traverses "bar", and attempts to find "baz", which it does
- not find (the "bar" resource raises a :exc:`KeyError` when asked for
- "baz").
+ not find (the "bar" resource raises a :exc:`KeyError` when asked for "baz").
The fact that it does not find "baz" at this point does not signify an error
-condition. It signifies that:
+condition. It signifies the following:
-- the :term:`context` is the "bar" resource (the context is the last resource
+- The :term:`context` is the "bar" resource (the context is the last resource
found during traversal).
-- the :term:`view name` is ``baz``
+- The :term:`view name` is ``baz``.
-- the :term:`subpath` is ``('biz', 'buz.txt')``
+- The :term:`subpath` is ``('biz', 'buz.txt')``.
At this point, traversal has ended, and :term:`view lookup` begins.
Because it's the "context" resource, the view lookup machinery examines "bar"
-to find out what "type" it is. Let's say it finds that the context is a
-``Bar`` type (because "bar" happens to be an instance of the class ``Bar``).
-Using the :term:`view name` (``baz``) and the type, view lookup asks the
+to find out what "type" it is. Let's say it finds that the context is a ``Bar``
+type (because "bar" happens to be an instance of the class ``Bar``). Using the
+:term:`view name` (``baz``) and the type, view lookup asks the
:term:`application registry` this question:
- Please find me a :term:`view callable` registered using a :term:`view
configuration` with the name "baz" that can be used for the class ``Bar``.
-Let's say that view lookup finds no matching view type. In this
-circumstance, the :app:`Pyramid` :term:`router` returns the result of the
-:term:`Not Found View` and the request ends.
+Let's say that view lookup finds no matching view type. In this circumstance,
+the :app:`Pyramid` :term:`router` returns the result of the :term:`Not Found
+View` and the request ends.
However, for this tree:
@@ -399,59 +387,58 @@ The user asks for ``http://example.com/foo/bar/baz/biz/buz.txt``
- :term:`traversal` traverses "baz", and attempts to find "biz", which it
finds.
-- :term:`traversal` traverses "biz", and attempts to find "buz.txt" which it
+- :term:`traversal` traverses "biz", and attempts to find "buz.txt", which it
does not find.
The fact that it does not find a resource related to "buz.txt" at this point
-does not signify an error condition. It signifies that:
+does not signify an error condition. It signifies the following:
-- the :term:`context` is the "biz" resource (the context is the last resource
+- The :term:`context` is the "biz" resource (the context is the last resource
found during traversal).
-- the :term:`view name` is "buz.txt"
+- The :term:`view name` is "buz.txt".
-- the :term:`subpath` is an empty sequence ( ``()`` ).
+- The :term:`subpath` is an empty sequence ( ``()`` ).
At this point, traversal has ended, and :term:`view lookup` begins.
Because it's the "context" resource, the view lookup machinery examines the
"biz" resource to find out what "type" it is. Let's say it finds that the
resource is a ``Biz`` type (because "biz" is an instance of the Python class
-``Biz``). Using the :term:`view name` (``buz.txt``) and the type, view
-lookup asks the :term:`application registry` this question:
+``Biz``). Using the :term:`view name` (``buz.txt``) and the type, view lookup
+asks the :term:`application registry` this question:
- Please find me a :term:`view callable` registered with a :term:`view
- configuration` with the name ``buz.txt`` that can be used for class
- ``Biz``.
+ configuration` with the name ``buz.txt`` that can be used for class ``Biz``.
-Let's say that question is answered by the application registry; in such a
-situation, the application registry returns a :term:`view callable`. The
-view callable is then called with the current :term:`WebOb` :term:`request`
-as the sole argument: ``request``; it is expected to return a response.
+Let's say that question is answered by the application registry. In such a
+situation, the application registry returns a :term:`view callable`. The view
+callable is then called with the current :term:`WebOb` :term:`request` as the
+sole argument, ``request``. It is expected to return a response.
-.. sidebar:: The Example View Callables Accept Only a Request; How Do I Access the Context Resource?
+.. sidebar:: The Example View Callables Accept Only a Request; How Do I Access
+ the Context Resource?
- Most of the examples in this book assume that a view callable is typically
- passed only a :term:`request` object. Sometimes your view callables need
- access to the :term:`context` resource, especially when you use
- :term:`traversal`. You might use a supported alternate view callable
+ Most of the examples in this documentation assume that a view callable is
+ typically passed only a :term:`request` object. Sometimes your view
+ callables need access to the :term:`context` resource, especially when you
+ use :term:`traversal`. You might use a supported alternative view callable
argument list in your view callables such as the ``(context, request)``
- calling convention described in
- :ref:`request_and_context_view_definitions`. But you don't need to if you
- don't want to. In view callables that accept only a request, the
- :term:`context` resource found by traversal is available as the
- ``context`` attribute of the request object, e.g. ``request.context``.
- The :term:`view name` is available as the ``view_name`` attribute of the
- request object, e.g. ``request.view_name``. Other :app:`Pyramid`
- -specific request attributes are also available as described in
- :ref:`special_request_attributes`.
+ calling convention described in :ref:`request_and_context_view_definitions`.
+ But you don't need to if you don't want to. In view callables that accept
+ only a request, the :term:`context` resource found by traversal is available
+ as the ``context`` attribute of the request object, e.g.,
+ ``request.context``. The :term:`view name` is available as the ``view_name``
+ attribute of the request object, e.g., ``request.view_name``. Other
+ :app:`Pyramid`-specific request attributes are also available as described
+ in :ref:`special_request_attributes`.
.. index::
single: resource interfaces
.. _using_resource_interfaces:
-Using Resource Interfaces In View Configuration
+Using Resource Interfaces in View Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of registering your views with a ``context`` that names a Python
@@ -460,18 +447,17 @@ resource *class*, you can optionally register a view callable with a
arbitrarily to any resource object. View lookup treats context interfaces
specially, and therefore the identity of a resource can be divorced from that
of the class which implements it. As a result, associating a view with an
-interface can provide more flexibility for sharing a single view between two
-or more different implementations of a resource type. For example, if two
-resource objects of different Python class types share the same interface,
-you can use the same view configuration to specify both of them as a
-``context``.
+interface can provide more flexibility for sharing a single view between two or
+more different implementations of a resource type. For example, if two
+resource objects of different Python class types share the same interface, you
+can use the same view configuration to specify both of them as a ``context``.
In order to make use of interfaces in your application during view dispatch,
you must create an interface and mark up your resource classes or instances
with interface declarations that refer to this interface.
-To attach an interface to a resource *class*, you define the interface and
-use the :func:`zope.interface.implementer` class decorator to associate the
+To attach an interface to a resource *class*, you define the interface and use
+the :func:`zope.interface.implementer` class decorator to associate the
interface with the class.
.. code-block:: python
@@ -488,9 +474,9 @@ interface with the class.
pass
To attach an interface to a resource *instance*, you define the interface and
-use the :func:`zope.interface.alsoProvides` function to associate the
-interface with the instance. This function mutates the instance in such a
-way that the interface is attached to it.
+use the :func:`zope.interface.alsoProvides` function to associate the interface
+with the instance. This function mutates the instance in such a way that the
+interface is attached to it.
.. code-block:: python
:linenos:
@@ -509,13 +495,13 @@ way that the interface is attached to it.
alsoProvides(hello, IHello)
return hello
-Regardless of how you associate an interface, with a resource instance, or a
-resource class, the resulting code to associate that interface with a view
+Regardless of how you associate an interface—with either a resource instance
+or a resource class—the resulting code to associate that interface with a view
callable is the same. Assuming the above code that defines an ``IHello``
interface lives in the root of your application, and its module is named
"resources.py", the interface declaration below will associate the
-``mypackage.views.hello_world`` view with resources that implement, or
-provide, this interface.
+``mypackage.views.hello_world`` view with resources that implement, or provide,
+this interface.
.. code-block:: python
:linenos:
@@ -525,20 +511,18 @@ provide, this interface.
config.add_view('mypackage.views.hello_world', name='hello.html',
context='mypackage.resources.IHello')
-Any time a resource that is determined to be the :term:`context` provides
-this interface, and a view named ``hello.html`` is looked up against it as
-per the URL, the ``mypackage.views.hello_world`` view callable will be
-invoked.
-
-Note, in cases where a view is registered against a resource class, and a
-view is also registered against an interface that the resource class
-implements, an ambiguity arises. Views registered for the resource class take
-precedence over any views registered for any interface the resource class
-implements. Thus, if one view configuration names a ``context`` of both the
-class type of a resource, and another view configuration names a ``context``
-of interface implemented by the resource's class, and both view
-configurations are otherwise identical, the view registered for the context's
-class will "win".
+Any time a resource that is determined to be the :term:`context` provides this
+interface, and a view named ``hello.html`` is looked up against it as per the
+URL, the ``mypackage.views.hello_world`` view callable will be invoked.
+
+Note, in cases where a view is registered against a resource class, and a view
+is also registered against an interface that the resource class implements, an
+ambiguity arises. Views registered for the resource class take precedence over
+any views registered for any interface the resource class implements. Thus, if
+one view configuration names a ``context`` of both the class type of a
+resource, and another view configuration names a ``context`` of interface
+implemented by the resource's class, and both view configurations are otherwise
+identical, the view registered for the context's class will "win".
For more information about defining resources with interfaces for use within
view configuration, see :ref:`resources_which_implement_interfaces`.
@@ -558,4 +542,3 @@ traversal, such as traversal invocation from within application code.
The :meth:`pyramid.request.Request.resource_url` method generates a URL when
given a resource retrieved from a resource tree.
-
diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst
index eb3194a65..db9b5e090 100644
--- a/docs/narr/upgrading.rst
+++ b/docs/narr/upgrading.rst
@@ -12,26 +12,26 @@ applications keep working when you upgrade the Pyramid version you're using.
.. sidebar:: About Release Numbering
Conventionally, application version numbering in Python is described as
- ``major.minor.micro``. If your Pyramid version is "1.2.3", it means
- you're running a version of Pyramid with the major version "1", the minor
- version "2" and the micro version "3". A "major" release is one that
- increments the first-dot number; 2.X.X might follow 1.X.X. A "minor"
- release is one that increments the second-dot number; 1.3.X might follow
- 1.2.X. A "micro" release is one that increments the third-dot number;
- 1.2.3 might follow 1.2.2. In general, micro releases are "bugfix-only",
- and contain no new features, minor releases contain new features but are
- largely backwards compatible with older versions, and a major release
- indicates a large set of backwards incompatibilities.
+ ``major.minor.micro``. If your Pyramid version is "1.2.3", it means you're
+ running a version of Pyramid with the major version "1", the minor version
+ "2" and the micro version "3". A "major" release is one that increments the
+ first-dot number; 2.X.X might follow 1.X.X. A "minor" release is one that
+ increments the second-dot number; 1.3.X might follow 1.2.X. A "micro"
+ release is one that increments the third-dot number; 1.2.3 might follow
+ 1.2.2. In general, micro releases are "bugfix-only", and contain no new
+ features, minor releases contain new features but are largely backwards
+ compatible with older versions, and a major release indicates a large set of
+ backwards incompatibilities.
The Pyramid core team is conservative when it comes to removing features. We
-don't remove features unnecessarily, but we're human, and we make mistakes
-which cause some features to be evolutionary dead ends. Though we are
-willing to support dead-end features for some amount of time, some eventually
-have to be removed when the cost of supporting them outweighs the benefit of
-keeping them around, because each feature in Pyramid represents a certain
-documentation and maintenance burden.
-
-Deprecation and Removal Policy
+don't remove features unnecessarily, but we're human and we make mistakes which
+cause some features to be evolutionary dead ends. Though we are willing to
+support dead-end features for some amount of time, some eventually have to be
+removed when the cost of supporting them outweighs the benefit of keeping them
+around, because each feature in Pyramid represents a certain documentation and
+maintenance burden.
+
+Deprecation and removal policy
------------------------------
When a feature is scheduled for removal from Pyramid or any of its official
@@ -51,50 +51,49 @@ When a deprecated feature is eventually removed:
- A note is added to the :ref:`changelog` about the removal.
-Features are never removed in *micro* releases. They are only removed in
-minor and major releases. Deprecated features are kept around for at least
-*three* minor releases from the time the feature became deprecated.
-Therefore, if a feature is added in Pyramid 1.0, but it's deprecated in
-Pyramid 1.1, it will be kept around through all 1.1.X releases, all 1.2.X
-releases and all 1.3.X releases. It will finally be removed in the first
-1.4.X release.
-
-Sometimes features are "docs-deprecated" instead of formally deprecated.
-This means that the feature will be kept around indefinitely, but it will be
-removed from the documentation or a note will be added to the documentation
-telling folks to use some other newer feature. This happens when the cost of
-keeping an old feature around is very minimal and the support and
-documentation burden is very low. For example, we might rename a function
-that is an API without changing the arguments it accepts. In this case,
-we'll often rename the function, and change the docs to point at the new
-function name, but leave around a backwards compatibility alias to the old
-function name so older code doesn't break.
+Features are never removed in *micro* releases. They are only removed in minor
+and major releases. Deprecated features are kept around for at least *three*
+minor releases from the time the feature became deprecated. Therefore, if a
+feature is added in Pyramid 1.0, but it's deprecated in Pyramid 1.1, it will be
+kept around through all 1.1.X releases, all 1.2.X releases and all 1.3.X
+releases. It will finally be removed in the first 1.4.X release.
+
+Sometimes features are "docs-deprecated" instead of formally deprecated. This
+means that the feature will be kept around indefinitely, but it will be removed
+from the documentation or a note will be added to the documentation telling
+folks to use some other newer feature. This happens when the cost of keeping
+an old feature around is very minimal and the support and documentation burden
+is very low. For example, we might rename a function that is an API without
+changing the arguments it accepts. In this case, we'll often rename the
+function, and change the docs to point at the new function name, but leave
+around a backwards compatibility alias to the old function name so older code
+doesn't break.
"Docs deprecated" features tend to work "forever", meaning that they won't be
removed, and they'll never generate a deprecation warning. However, such
changes are noted in the :ref:`changelog`, so it's possible to know that you
-should change older spellings to newer ones to ensure that people reading
-your code can find the APIs you're using in the Pyramid docs.
+should change older spellings to newer ones to ensure that people reading your
+code can find the APIs you're using in the Pyramid docs.
-Consulting the Change History
+Consulting the change history
-----------------------------
-Your first line of defense against application failures caused by upgrading
-to a newer Pyramid release is always to read the :ref:`changelog`. to find
-the deprecations and removals for each release between the release you're
-currently running and the one you wish to upgrade to. The change history
-notes every deprecation within a ``Deprecation`` section and every removal
-within a ``Backwards Incompatibilies`` section for each release.
+Your first line of defense against application failures caused by upgrading to
+a newer Pyramid release is always to read the :ref:`changelog` to find the
+deprecations and removals for each release between the release you're currently
+running and the one to which you wish to upgrade. The change history notes
+every deprecation within a ``Deprecation`` section and every removal within a
+``Backwards Incompatibilies`` section for each release.
-The change history often contains instructions for changing your code to
-avoid deprecation warnings and how to change docs-deprecated spellings to
-newer ones. You can follow along with each deprecation explanation in the
-change history, simply doing a grep or other code search to your application,
-using the change log examples to remediate each potential problem.
+The change history often contains instructions for changing your code to avoid
+deprecation warnings and how to change docs-deprecated spellings to newer ones.
+You can follow along with each deprecation explanation in the change history,
+simply doing a grep or other code search to your application, using the change
+log examples to remediate each potential problem.
.. _testing_under_new_release:
-Testing Your Application Under a New Pyramid Release
+Testing your application under a new Pyramid release
----------------------------------------------------
Once you've upgraded your application to a new Pyramid release and you've
@@ -106,25 +105,24 @@ you can see DeprecationWarnings printed to the console when the tests run.
$ python -Wd setup.py test -q
-The ``-Wd`` argument is an argument that tells Python to print deprecation
-warnings to the console. Note that the ``-Wd`` flag is only required for
-Python 2.7 and better: Python versions 2.6 and older print deprecation
-warnings to the console by default. See `the Python -W flag documentation
-<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
-information.
+The ``-Wd`` argument tells Python to print deprecation warnings to the console.
+Note that the ``-Wd`` flag is only required for Python 2.7 and better: Python
+versions 2.6 and older print deprecation warnings to the console by default.
+See `the Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more information.
As your tests run, deprecation warnings will be printed to the console
-explaining the deprecation and providing instructions about how to prevent
-the deprecation warning from being issued. For example:
+explaining the deprecation and providing instructions about how to prevent the
+deprecation warning from being issued. For example:
-.. code-block:: text
+.. code-block:: bash
$ python -Wd setup.py test -q
# .. elided ...
running build_ext
- /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
- DeprecationWarning: static: The "pyramid.view.static" class is deprecated
- as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
+ /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
+ DeprecationWarning: static: The "pyramid.view.static" class is deprecated
+ as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
the "use_subpath" argument set to True.
from pyramid.view import static
.
@@ -144,8 +142,8 @@ pyramid.view import static``) that is causing the problem:
from pyramid.view import static
myview = static('static', 'static')
-The deprecation warning tells me how to fix it, so I can change the code to
-do things the newer way:
+The deprecation warning tells me how to fix it, so I can change the code to do
+things the newer way:
.. code-block:: python
:linenos:
@@ -155,10 +153,10 @@ do things the newer way:
from pyramid.static import static_view
myview = static_view('static', 'static', use_subpath=True)
-When I run the tests again, the deprecation warning is no longer printed to
-my console:
+When I run the tests again, the deprecation warning is no longer printed to my
+console:
-.. code-block:: text
+.. code-block:: bash
$ python -Wd setup.py test -q
# .. elided ...
@@ -170,7 +168,7 @@ my console:
OK
-My Application Doesn't Have Any Tests or Has Few Tests
+My application doesn't have any tests or has few tests
------------------------------------------------------
If your application has no tests, or has only moderate test coverage, running
@@ -178,8 +176,8 @@ tests won't tell you very much, because the Pyramid codepaths that generate
deprecation warnings won't be executed.
In this circumstance, you can start your application interactively under a
-server run with the ``PYTHONWARNINGS`` environment variable set to
-``default``. On UNIX, you can do that via:
+server run with the ``PYTHONWARNINGS`` environment variable set to ``default``.
+On UNIX, you can do that via:
.. code-block:: bash
@@ -194,16 +192,15 @@ On Windows, you need to issue two commands:
At this point, it's ensured that deprecation warnings will be printed to the
console whenever a codepath is hit that generates one. You can then click
-around in your application interactively to try to generate them, and
-remediate as explained in :ref:`testing_under_new_release`.
+around in your application interactively to try to generate them, and remediate
+as explained in :ref:`testing_under_new_release`.
See `the PYTHONWARNINGS environment variable documentation
<http://docs.python.org/using/cmdline.html#envvar-PYTHONWARNINGS>`_ or `the
Python -W flag documentation
-<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
-information.
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more information.
-Upgrading to the Very Latest Pyramid Release
+Upgrading to the very latest Pyramid release
--------------------------------------------
When you upgrade your application to the most recent Pyramid release,
@@ -220,15 +217,13 @@ advisable to do this:
:ref:`testing_under_new_release`. Note any deprecation warnings and
remediate.
-- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's
- tests, note any deprecation warnings and remediate.
+- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's tests,
+ note any deprecation warnings, and remediate.
- Upgrade to 1.4.4. Run your application's tests, note any deprecation
- warnings and remediate.
+ warnings, and remediate.
If you skip testing your application under each minor release (for example if
-you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation
-warning and waste more time trying to figure out an error caused by a feature
-removal than it would take to upgrade stepwise through each minor release.
-
-
+you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation warning
+and waste more time trying to figure out an error caused by a feature removal
+than it would take to upgrade stepwise through each minor release.
diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst
index b0e9b1709..784886563 100644
--- a/docs/narr/zca.rst
+++ b/docs/narr/zca.rst
@@ -9,17 +9,16 @@
.. _zca_chapter:
Using the Zope Component Architecture in :app:`Pyramid`
-==========================================================
+=======================================================
-Under the hood, :app:`Pyramid` uses a :term:`Zope Component
-Architecture` component registry as its :term:`application registry`.
-The Zope Component Architecture is referred to colloquially as the
-"ZCA."
+Under the hood, :app:`Pyramid` uses a :term:`Zope Component Architecture`
+component registry as its :term:`application registry`. The Zope Component
+Architecture is referred to colloquially as the "ZCA."
The ``zope.component`` API used to access data in a traditional Zope
-application can be opaque. For example, here is a typical "unnamed
-utility" lookup using the :func:`zope.component.getUtility` global API
-as it might appear in a traditional Zope application:
+application can be opaque. For example, here is a typical "unnamed utility"
+lookup using the :func:`zope.component.getUtility` global API as it might
+appear in a traditional Zope application:
.. code-block:: python
:linenos:
@@ -28,23 +27,21 @@ as it might appear in a traditional Zope application:
from zope.component import getUtility
settings = getUtility(ISettings)
-After this code runs, ``settings`` will be a Python dictionary. But
-it's unlikely that any "civilian" will be able to figure this out just
-by reading the code casually. When the ``zope.component.getUtility``
-API is used by a developer, the conceptual load on a casual reader of
-code is high.
+After this code runs, ``settings`` will be a Python dictionary. But it's
+unlikely that any "civilian" will be able to figure this out just by reading
+the code casually. When the ``zope.component.getUtility`` API is used by a
+developer, the conceptual load on a casual reader of code is high.
-While the ZCA is an excellent tool with which to build a *framework*
-such as :app:`Pyramid`, it is not always the best tool with which
-to build an *application* due to the opacity of the ``zope.component``
-APIs. Accordingly, :app:`Pyramid` tends to hide the presence of the
-ZCA from application developers. You needn't understand the ZCA to
-create a :app:`Pyramid` application; its use is effectively only a
-framework implementation detail.
+While the ZCA is an excellent tool with which to build a *framework* such as
+:app:`Pyramid`, it is not always the best tool with which to build an
+*application* due to the opacity of the ``zope.component`` APIs. Accordingly,
+:app:`Pyramid` tends to hide the presence of the ZCA from application
+developers. You needn't understand the ZCA to create a :app:`Pyramid`
+application; its use is effectively only a framework implementation detail.
-However, developers who are already used to writing :term:`Zope`
-applications often still wish to use the ZCA while building a
-:app:`Pyramid` application; :app:`Pyramid` makes this possible.
+However, developers who are already used to writing :term:`Zope` applications
+often still wish to use the ZCA while building a :app:`Pyramid` application.
+:app:`Pyramid` makes this possible.
.. index::
single: get_current_registry
@@ -52,87 +49,81 @@ applications often still wish to use the ZCA while building a
single: getSiteManager
single: ZCA global API
-Using the ZCA Global API in a :app:`Pyramid` Application
------------------------------------------------------------
-
-:term:`Zope` uses a single ZCA registry -- the "global" ZCA registry
--- for all Zope applications that run in the same Python process,
-effectively making it impossible to run more than one Zope application
-in a single process.
-
-However, for ease of deployment, it's often useful to be able to run more
-than a single application per process. For example, use of a
-:term:`PasteDeploy` "composite" allows you to run separate individual WSGI
-applications in the same process, each answering requests for some URL
-prefix. This makes it possible to run, for example, a TurboGears application
-at ``/turbogears`` and a :app:`Pyramid` application at ``/pyramid``, both
-served up using the same :term:`WSGI` server within a single Python process.
-
-Most production Zope applications are relatively large, making it
-impractical due to memory constraints to run more than one Zope
-application per Python process. However, a :app:`Pyramid` application
-may be very small and consume very little memory, so it's a reasonable
-goal to be able to run more than one :app:`Pyramid` application per
-process.
-
-In order to make it possible to run more than one :app:`Pyramid`
-application in a single process, :app:`Pyramid` defaults to using a
-separate ZCA registry *per application*.
-
-While this services a reasonable goal, it causes some issues when
-trying to use patterns which you might use to build a typical
-:term:`Zope` application to build a :app:`Pyramid` application.
-Without special help, ZCA "global" APIs such as
-:func:`zope.component.getUtility` and :func:`zope.component.getSiteManager`
-will use the ZCA "global" registry. Therefore, these APIs
-will appear to fail when used in a :app:`Pyramid` application,
-because they'll be consulting the ZCA global registry rather than the
-component registry associated with your :app:`Pyramid` application.
-
-There are three ways to fix this: by disusing the ZCA global API
-entirely, by using
-:meth:`pyramid.config.Configurator.hook_zca` or by passing
-the ZCA global registry to the :term:`Configurator` constructor at
-startup time. We'll describe all three methods in this section.
+Using the ZCA global API in a :app:`Pyramid` application
+--------------------------------------------------------
+
+:term:`Zope` uses a single ZCA registry—the "global" ZCA registry—for all Zope
+applications that run in the same Python process, effectively making it
+impossible to run more than one Zope application in a single process.
+
+However, for ease of deployment, it's often useful to be able to run more than
+a single application per process. For example, use of a :term:`PasteDeploy`
+"composite" allows you to run separate individual WSGI applications in the same
+process, each answering requests for some URL prefix. This makes it possible
+to run, for example, a TurboGears application at ``/turbogears`` and a
+:app:`Pyramid` application at ``/pyramid``, both served up using the same
+:term:`WSGI` server within a single Python process.
+
+Most production Zope applications are relatively large, making it impractical
+due to memory constraints to run more than one Zope application per Python
+process. However, a :app:`Pyramid` application may be very small and consume
+very little memory, so it's a reasonable goal to be able to run more than one
+:app:`Pyramid` application per process.
+
+In order to make it possible to run more than one :app:`Pyramid` application in
+a single process, :app:`Pyramid` defaults to using a separate ZCA registry *per
+application*.
+
+While this services a reasonable goal, it causes some issues when trying to use
+patterns which you might use to build a typical :term:`Zope` application to
+build a :app:`Pyramid` application. Without special help, ZCA "global" APIs
+such as :func:`zope.component.getUtility` and
+:func:`zope.component.getSiteManager` will use the ZCA "global" registry.
+Therefore, these APIs will appear to fail when used in a :app:`Pyramid`
+application, because they'll be consulting the ZCA global registry rather than
+the component registry associated with your :app:`Pyramid` application.
+
+There are three ways to fix this: by disusing the ZCA global API entirely, by
+using :meth:`pyramid.config.Configurator.hook_zca` or by passing the ZCA global
+registry to the :term:`Configurator` constructor at startup time. We'll
+describe all three methods in this section.
.. index::
single: request.registry
.. _disusing_the_global_zca_api:
-Disusing the Global ZCA API
+Disusing the global ZCA API
+++++++++++++++++++++++++++
ZCA "global" API functions such as ``zope.component.getSiteManager``,
``zope.component.getUtility``, :func:`zope.component.getAdapter`, and
:func:`zope.component.getMultiAdapter` aren't strictly necessary. Every
-component registry has a method API that offers the same
-functionality; it can be used instead. For example, presuming the
-``registry`` value below is a Zope Component Architecture component
-registry, the following bit of code is equivalent to
-``zope.component.getUtility(IFoo)``:
+component registry has a method API that offers the same functionality; it can
+be used instead. For example, presuming the ``registry`` value below is a Zope
+Component Architecture component registry, the following bit of code is
+equivalent to ``zope.component.getUtility(IFoo)``:
.. code-block:: python
registry.getUtility(IFoo)
-The full method API is documented in the ``zope.component`` package,
-but it largely mirrors the "global" API almost exactly.
+The full method API is documented in the ``zope.component`` package, but it
+largely mirrors the "global" API almost exactly.
-If you are willing to disuse the "global" ZCA APIs and use the method
-interface of a registry instead, you need only know how to obtain the
-:app:`Pyramid` component registry.
+If you are willing to disuse the "global" ZCA APIs and use the method interface
+of a registry instead, you need only know how to obtain the :app:`Pyramid`
+component registry.
There are two ways of doing so:
-- use the :func:`pyramid.threadlocal.get_current_registry`
- function within :app:`Pyramid` view or resource code. This will
- always return the "current" :app:`Pyramid` application registry.
+- use the :func:`pyramid.threadlocal.get_current_registry` function within
+ :app:`Pyramid` view or resource code. This will always return the "current"
+ :app:`Pyramid` application registry.
-- use the attribute of the :term:`request` object named ``registry``
- in your :app:`Pyramid` view code, eg. ``request.registry``. This
- is the ZCA component registry related to the running
- :app:`Pyramid` application.
+- use the attribute of the :term:`request` object named ``registry`` in your
+ :app:`Pyramid` view code, e.g., ``request.registry``. This is the ZCA
+ component registry related to the running :app:`Pyramid` application.
See :ref:`threadlocals_chapter` for more information about
:func:`pyramid.threadlocal.get_current_registry`.
@@ -142,7 +133,7 @@ See :ref:`threadlocals_chapter` for more information about
.. _hook_zca:
-Enabling the ZCA Global API by Using ``hook_zca``
+Enabling the ZCA global API by using ``hook_zca``
+++++++++++++++++++++++++++++++++++++++++++++++++
Consider the following bit of idiomatic :app:`Pyramid` startup code:
@@ -157,34 +148,31 @@ Consider the following bit of idiomatic :app:`Pyramid` startup code:
config.include('some.other.package')
return config.make_wsgi_app()
-When the ``app`` function above is run, a :term:`Configurator` is
-constructed. When the configurator is created, it creates a *new*
-:term:`application registry` (a ZCA component registry). A new
-registry is constructed whenever the ``registry`` argument is omitted
-when a :term:`Configurator` constructor is called, or when a
-``registry`` argument with a value of ``None`` is passed to a
-:term:`Configurator` constructor.
-
-During a request, the application registry created by the Configurator
-is "made current". This means calls to
-:func:`~pyramid.threadlocal.get_current_registry` in the thread
-handling the request will return the component registry associated
-with the application.
-
-As a result, application developers can use ``get_current_registry``
-to get the registry and thus get access to utilities and such, as per
-:ref:`disusing_the_global_zca_api`. But they still cannot use the
-global ZCA API. Without special treatment, the ZCA global APIs will
-always return the global ZCA registry (the one in
-``zope.component.globalregistry.base``).
-
-To "fix" this and make the ZCA global APIs use the "current"
-:app:`Pyramid` registry, you need to call
-:meth:`~pyramid.config.Configurator.hook_zca` within your setup code.
-For example:
+When the ``app`` function above is run, a :term:`Configurator` is constructed.
+When the configurator is created, it creates a *new* :term:`application
+registry` (a ZCA component registry). A new registry is constructed whenever
+the ``registry`` argument is omitted, when a :term:`Configurator` constructor
+is called, or when a ``registry`` argument with a value of ``None`` is passed
+to a :term:`Configurator` constructor.
+
+During a request, the application registry created by the Configurator is "made
+current". This means calls to
+:func:`~pyramid.threadlocal.get_current_registry` in the thread handling the
+request will return the component registry associated with the application.
+
+As a result, application developers can use ``get_current_registry`` to get the
+registry and thus get access to utilities and such, as per
+:ref:`disusing_the_global_zca_api`. But they still cannot use the global ZCA
+API. Without special treatment, the ZCA global APIs will always return the
+global ZCA registry (the one in ``zope.component.globalregistry.base``).
+
+To "fix" this and make the ZCA global APIs use the "current" :app:`Pyramid`
+registry, you need to call :meth:`~pyramid.config.Configurator.hook_zca` within
+your setup code. For example:
.. code-block:: python
:linenos:
+ :emphasize-lines: 5
from pyramid.config import Configurator
@@ -194,9 +182,9 @@ For example:
config.include('some.other.application')
return config.make_wsgi_app()
-We've added a line to our original startup code, line number 6, which
-calls ``config.hook_zca()``. The effect of this line under the hood
-is that an analogue of the following code is executed:
+We've added a line to our original startup code, line number 5, which calls
+``config.hook_zca()``. The effect of this line under the hood is that an
+analogue of the following code is executed:
.. code-block:: python
:linenos:
@@ -205,17 +193,15 @@ is that an analogue of the following code is executed:
from pyramid.threadlocal import get_current_registry
getSiteManager.sethook(get_current_registry)
-This causes the ZCA global API to start using the :app:`Pyramid`
-application registry in threads which are running a :app:`Pyramid`
-request.
+This causes the ZCA global API to start using the :app:`Pyramid` application
+registry in threads which are running a :app:`Pyramid` request.
-Calling ``hook_zca`` is usually sufficient to "fix" the problem of
-being able to use the global ZCA API within a :app:`Pyramid`
-application. However, it also means that a Zope application that is
-running in the same process may start using the :app:`Pyramid`
-global registry instead of the Zope global registry, effectively
-inverting the original problem. In such a case, follow the steps in
-the next section, :ref:`using_the_zca_global_registry`.
+Calling ``hook_zca`` is usually sufficient to "fix" the problem of being able
+to use the global ZCA API within a :app:`Pyramid` application. However, it
+also means that a Zope application that is running in the same process may
+start using the :app:`Pyramid` global registry instead of the Zope global
+registry, effectively inverting the original problem. In such a case, follow
+the steps in the next section, :ref:`using_the_zca_global_registry`.
.. index::
single: get_current_registry
@@ -224,14 +210,15 @@ the next section, :ref:`using_the_zca_global_registry`.
.. _using_the_zca_global_registry:
-Enabling the ZCA Global API by Using The ZCA Global Registry
+Enabling the ZCA global API by using the ZCA global registry
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-You can tell your :app:`Pyramid` application to use the ZCA global
-registry at startup time instead of constructing a new one:
+You can tell your :app:`Pyramid` application to use the ZCA global registry at
+startup time instead of constructing a new one:
.. code-block:: python
:linenos:
+ :emphasize-lines: 5-7
from zope.component import getGlobalSiteManager
from pyramid.config import Configurator
@@ -243,16 +230,14 @@ registry at startup time instead of constructing a new one:
config.include('some.other.application')
return config.make_wsgi_app()
-Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves
-the global ZCA component registry. Line 6 creates a
-:term:`Configurator`, passing the global ZCA registry into its
-constructor as the ``registry`` argument. Line 7 "sets up" the global
-registry with Pyramid-specific registrations; this is code that is
-normally executed when a registry is constructed rather than created,
+Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves the global
+ZCA component registry. Line 6 creates a :term:`Configurator`, passing the
+global ZCA registry into its constructor as the ``registry`` argument. Line 7
+"sets up" the global registry with Pyramid-specific registrations; this is code
+that is normally executed when a registry is constructed rather than created,
but we must call it "by hand" when we pass an explicit registry.
-At this point, :app:`Pyramid` will use the ZCA global registry
-rather than creating a new application-specific registry; since by
-default the ZCA global API will use this registry, things will work as
-you might expect a Zope app to when you use the global ZCA API.
-
+At this point, :app:`Pyramid` will use the ZCA global registry rather than
+creating a new application-specific registry. Since by default the ZCA global
+API will use this registry, things will work as you might expect in a Zope app
+when you use the global ZCA API.
diff --git a/docs/pscripts/index.rst b/docs/pscripts/index.rst
new file mode 100644
index 000000000..857e0564f
--- /dev/null
+++ b/docs/pscripts/index.rst
@@ -0,0 +1,12 @@
+.. _pscripts_documentation:
+
+``p*`` Scripts Documentation
+============================
+
+Command line programs (``p*`` scripts) included with :app:`Pyramid`.
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ *
diff --git a/docs/pscripts/pcreate.rst b/docs/pscripts/pcreate.rst
new file mode 100644
index 000000000..b5ec3f4e2
--- /dev/null
+++ b/docs/pscripts/pcreate.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: pcreate; --help
+
+.. _pcreate_script:
+
+``pcreate``
+-----------
+
+.. program-output:: pcreate --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`creating_a_project`
diff --git a/docs/pscripts/pdistreport.rst b/docs/pscripts/pdistreport.rst
new file mode 100644
index 000000000..1c53fb6e9
--- /dev/null
+++ b/docs/pscripts/pdistreport.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: pdistreport; --help
+
+.. _pdistreport_script:
+
+``pdistreport``
+---------------
+
+.. program-output:: pdistreport --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`showing_distributions`
diff --git a/docs/pscripts/prequest.rst b/docs/pscripts/prequest.rst
new file mode 100644
index 000000000..a15827767
--- /dev/null
+++ b/docs/pscripts/prequest.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: prequest; --help
+
+.. _prequest_script:
+
+``prequest``
+------------
+
+.. program-output:: prequest --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`invoking_a_request`
diff --git a/docs/pscripts/proutes.rst b/docs/pscripts/proutes.rst
new file mode 100644
index 000000000..09ed013e1
--- /dev/null
+++ b/docs/pscripts/proutes.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: proutes; --help
+
+.. _proutes_script:
+
+``proutes``
+-----------
+
+.. program-output:: proutes --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`displaying_application_routes`
diff --git a/docs/pscripts/pserve.rst b/docs/pscripts/pserve.rst
new file mode 100644
index 000000000..d33d4a484
--- /dev/null
+++ b/docs/pscripts/pserve.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: pserve; --help
+
+.. _pserve_script:
+
+``pserve``
+----------
+
+.. program-output:: pserve --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`running_the_project_application`
diff --git a/docs/pscripts/pshell.rst b/docs/pscripts/pshell.rst
new file mode 100644
index 000000000..cfd84d4f8
--- /dev/null
+++ b/docs/pscripts/pshell.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: pshell; --help
+
+.. _pshell_script:
+
+``pshell``
+----------
+
+.. program-output:: pshell --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`interactive_shell`
diff --git a/docs/pscripts/ptweens.rst b/docs/pscripts/ptweens.rst
new file mode 100644
index 000000000..02e23e49a
--- /dev/null
+++ b/docs/pscripts/ptweens.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: ptweens; --help
+
+.. _ptweens_script:
+
+``ptweens``
+-----------
+
+.. program-output:: ptweens --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`displaying_tweens`
diff --git a/docs/pscripts/pviews.rst b/docs/pscripts/pviews.rst
new file mode 100644
index 000000000..b4de5c054
--- /dev/null
+++ b/docs/pscripts/pviews.rst
@@ -0,0 +1,13 @@
+.. index::
+ single: pviews; --help
+
+.. _pviews_script:
+
+``pviews``
+----------
+
+.. program-output:: pviews --help
+ :prompt:
+ :shell:
+
+.. seealso:: :ref:`displaying_matching_views`
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 80ae4b34e..695d7f15b 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -220,7 +220,7 @@ We also need to create a declarative ``Base`` object to use as a
base class for our model:
.. literalinclude:: src/basiclayout/tutorial/models.py
- :lines: 17
+ :lines: 18
:language: py
Our model classes will inherit from this ``Base`` class so they can be
diff --git a/docs/whatsnew-1.0.rst b/docs/whatsnew-1.0.rst
index 9541f0a28..0ed6e21fc 100644
--- a/docs/whatsnew-1.0.rst
+++ b/docs/whatsnew-1.0.rst
@@ -1,4 +1,4 @@
-What's New In Pyramid 1.0
+What's New in Pyramid 1.0
=========================
This article explains the new features in Pyramid version 1.0 as compared to
diff --git a/docs/whatsnew-1.1.rst b/docs/whatsnew-1.1.rst
index 99737b6d8..a5c7f3393 100644
--- a/docs/whatsnew-1.1.rst
+++ b/docs/whatsnew-1.1.rst
@@ -1,4 +1,4 @@
-What's New In Pyramid 1.1
+What's New in Pyramid 1.1
=========================
This article explains the new features in Pyramid version 1.1 as compared to
diff --git a/docs/whatsnew-1.2.rst b/docs/whatsnew-1.2.rst
index a9fc38908..9ff933ace 100644
--- a/docs/whatsnew-1.2.rst
+++ b/docs/whatsnew-1.2.rst
@@ -1,4 +1,4 @@
-What's New In Pyramid 1.2
+What's New in Pyramid 1.2
=========================
This article explains the new features in :app:`Pyramid` version 1.2 as
diff --git a/docs/whatsnew-1.3.rst b/docs/whatsnew-1.3.rst
index 2606c3df3..1a299e126 100644
--- a/docs/whatsnew-1.3.rst
+++ b/docs/whatsnew-1.3.rst
@@ -1,4 +1,4 @@
-What's New In Pyramid 1.3
+What's New in Pyramid 1.3
=========================
This article explains the new features in :app:`Pyramid` version 1.3 as
diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst
index 505b9d798..fce889854 100644
--- a/docs/whatsnew-1.4.rst
+++ b/docs/whatsnew-1.4.rst
@@ -1,4 +1,4 @@
-What's New In Pyramid 1.4
+What's New in Pyramid 1.4
=========================
This article explains the new features in :app:`Pyramid` version 1.4 as
diff --git a/docs/whatsnew-1.5.rst b/docs/whatsnew-1.5.rst
index 1d863c937..a477ce5ec 100644
--- a/docs/whatsnew-1.5.rst
+++ b/docs/whatsnew-1.5.rst
@@ -1,4 +1,4 @@
-What's New In Pyramid 1.5
+What's New in Pyramid 1.5
=========================
This article explains the new features in :app:`Pyramid` version 1.5 as
@@ -136,6 +136,8 @@ Feature Additions
The feature additions in Pyramid 1.5 follow.
+- Python 3.4 compatibility.
+
- Add ``pdistreport`` script, which prints the Python version in use, the
Pyramid version in use, and the version number and location of all Python
distributions currently installed.
diff --git a/docs/whatsnew-1.6.rst b/docs/whatsnew-1.6.rst
index b99ebeec4..bdfcf34ab 100644
--- a/docs/whatsnew-1.6.rst
+++ b/docs/whatsnew-1.6.rst
@@ -1,40 +1,62 @@
-What's New In Pyramid 1.6
+What's New in Pyramid 1.6
=========================
This article explains the new features in :app:`Pyramid` version 1.6 as
-compared to its predecessor, :app:`Pyramid` 1.5. It also documents backwards
+compared to its predecessor, :app:`Pyramid` 1.5. It also documents backwards
incompatibilities between the two versions and deprecations added to
:app:`Pyramid` 1.6, as well as software dependency changes and notable
documentation additions.
+
Backwards Incompatibilities
---------------------------
+- IPython and BPython support have been removed from pshell in the core. To
+ continue using them on Pyramid 1.6+, you must install the binding packages
+ explicitly. One way to do this is by adding ``pyramid_ipython`` (or
+ ``pyramid_bpython``) to the ``install_requires`` section of your package's
+ ``setup.py`` file, then re-running ``setup.py develop``::
+
+ setup(
+ #...
+ install_requires=[
+ 'pyramid_ipython', # new dependency
+ 'pyramid',
+ #...
+ ],
+ )
+
- ``request.response`` will no longer be mutated when using the
- :func:`~pyramid.renderers.render_to_response` API. It is now necessary
- to pass in
- a ``response=`` argument to :func:`~pyramid.renderers.render_to_response` if
- you wish to supply the renderer with a custom response object for it to
- use. If you do not pass one then a response object will be created using the
- current response factory. Almost all renderers mutate the
- ``request.response`` response object (for example, the JSON renderer sets
- ``request.response.content_type`` to ``application/json``). However, when
- invoking ``render_to_response`` it is not expected that the response object
- being returned would be the same one used later in the request. The response
- object returned from ``render_to_response`` is now explicitly different from
- ``request.response``. This does not change the API of a renderer. See
+ :func:`~pyramid.renderers.render_to_response` API. It is now necessary to
+ pass in a ``response=`` argument to
+ :func:`~pyramid.renderers.render_to_response` if you wish to supply the
+ renderer with a custom response object. If you do not pass one, then a
+ response object will be created using the current response factory. Almost
+ all renderers mutate the ``request.response`` response object (for example,
+ the JSON renderer sets ``request.response.content_type`` to
+ ``application/json``). However, when invoking ``render_to_response``, it is
+ not expected that the response object being returned would be the same one
+ used later in the request. The response object returned from
+ ``render_to_response`` is now explicitly different from ``request.response``.
+ This does not change the API of a renderer. See
https://github.com/Pylons/pyramid/pull/1563
Feature Additions
-----------------
-- Cache busting for static assets has been added and is available via a new
- argument to :meth:`pyramid.config.Configurator.add_static_view`:
- ``cachebust``. Core APIs are shipped for both cache busting via query
- strings and path segments and may be extended to fit into custom asset
- pipelines. See https://github.com/Pylons/pyramid/pull/1380 and
- https://github.com/Pylons/pyramid/pull/1583
+- Python 3.5 and pypy3 compatibility.
+
+- ``pserve --reload`` will no longer crash on syntax errors. See
+ https://github.com/Pylons/pyramid/pull/2044
+
+- Cache busting for static resources has been added and is available via a new
+ :meth:`pyramid.config.Configurator.add_cache_buster` API. Core APIs are
+ shipped for both cache busting via query strings and via asset manifests for
+ integrating into custom asset pipelines. See
+ https://github.com/Pylons/pyramid/pull/1380 and
+ https://github.com/Pylons/pyramid/pull/1583 and
+ https://github.com/Pylons/pyramid/pull/2171
- Assets can now be overidden by an absolute path on the filesystem when using
the :meth:`~pyramid.config.Configurator.override_asset` API. This makes it
@@ -47,99 +69,129 @@ Feature Additions
``config.add_static_view('myapp:static', 'static')`` and
``config.override_asset(to_override='myapp:static/',
override_with='/abs/path/')``. The ``myapp:static`` asset spec is completely
- made up and does not need to exist - it is used for generating urls via
- ``request.static_url('myapp:static/foo.png')``. See
+ made up and does not need to exist—it is used for generating URLs via
+ ``request.static_url('myapp:static/foo.png')``. See
https://github.com/Pylons/pyramid/issues/1252
- Added :meth:`~pyramid.config.Configurator.set_response_factory` and the
``response_factory`` keyword argument to the constructor of
:class:`~pyramid.config.Configurator` for defining a factory that will return
- a custom ``Response`` class. See https://github.com/Pylons/pyramid/pull/1499
+ a custom ``Response`` class. See https://github.com/Pylons/pyramid/pull/1499
-- Add :attr:`pyramid.config.Configurator.root_package` attribute and init
- parameter to assist with includeable packages that wish to resolve
- resources relative to the package in which the configurator was created.
- This is especially useful for addons that need to load asset specs from
- settings, in which case it is may be natural for a developer to define
- imports or assets relative to the top-level package.
- See https://github.com/Pylons/pyramid/pull/1337
+- Added :attr:`pyramid.config.Configurator.root_package` attribute and init
+ parameter to assist with includible packages that wish to resolve resources
+ relative to the package in which the configurator was created. This is
+ especially useful for add-ons that need to load asset specs from settings, in
+ which case it may be natural for a developer to define imports or assets
+ relative to the top-level package. See
+ https://github.com/Pylons/pyramid/pull/1337
- Overall improvments for the ``proutes`` command. Added ``--format`` and
``--glob`` arguments to the command, introduced the ``method``
column for displaying available request methods, and improved the ``view``
- output by showing the module instead of just ``__repr__``.
- See https://github.com/Pylons/pyramid/pull/1488
+ output by showing the module instead of just ``__repr__``. See
+ https://github.com/Pylons/pyramid/pull/1488
- ``pserve`` can now take a ``-b`` or ``--browser`` option to open the server
URL in a web browser. See https://github.com/Pylons/pyramid/pull/1533
-- Support keyword-only arguments and function annotations in views in
- Python 3. See https://github.com/Pylons/pyramid/pull/1556
+- Support keyword-only arguments and function annotations in views in Python 3.
+ See https://github.com/Pylons/pyramid/pull/1556
- The ``append_slash`` argument of
:meth:`~pyramid.config.Configurator.add_notfound_view()` will now accept
anything that implements the :class:`~pyramid.interfaces.IResponse` interface
and will use that as the response class instead of the default
- :class:`~pyramid.httpexceptions.HTTPFound`. See
+ :class:`~pyramid.httpexceptions.HTTPFound`. See
https://github.com/Pylons/pyramid/pull/1610
- The :class:`~pyramid.config.Configurator` has grown the ability to allow
- actions to call other actions during a commit-cycle. This enables much more
+ actions to call other actions during a commit cycle. This enables much more
logic to be placed into actions, such as the ability to invoke other actions
or group them for improved conflict detection. We have also exposed and
- documented the config phases that Pyramid uses in order to further assist in
- building conforming addons. See https://github.com/Pylons/pyramid/pull/1513
+ documented the configuration phases that Pyramid uses in order to further
+ assist in building conforming add-ons. See
+ https://github.com/Pylons/pyramid/pull/1513
- Allow an iterator to be returned from a renderer. Previously it was only
- possible to return bytes or unicode.
- See https://github.com/Pylons/pyramid/pull/1417
+ possible to return bytes or unicode. See
+ https://github.com/Pylons/pyramid/pull/1417
- Improve robustness to timing attacks in the
:class:`~pyramid.authentication.AuthTktCookieHelper` and the
:class:`~pyramid.session.SignedCookieSessionFactory` classes by using the
- stdlib's ``hmac.compare_digest`` if it is available (such as Python 2.7.7+ and
- 3.3+). See https://github.com/Pylons/pyramid/pull/1457
+ stdlib's ``hmac.compare_digest`` if it is available (such as Python 2.7.7+
+ and 3.3+). See https://github.com/Pylons/pyramid/pull/1457
-- Improve the readability of the ``pcreate`` shell script output.
- See https://github.com/Pylons/pyramid/pull/1453
+- Improve the readability of the ``pcreate`` shell script output. See
+ https://github.com/Pylons/pyramid/pull/1453
-- Make it simple to define notfound and forbidden views that wish to use the
- default exception-response view but with altered predicates and other
- configuration options. The ``view`` argument is now optional in
+- Make it simple to define ``notfound`` and ``forbidden`` views that wish to
+ use the default exception-response view, but with altered predicates and
+ other configuration options. The ``view`` argument is now optional in
:meth:`~pyramid.config.Configurator.add_notfound_view` and
:meth:`~pyramid.config.Configurator.add_forbidden_view` See
https://github.com/Pylons/pyramid/issues/494
- The ``pshell`` script will now load a ``PYTHONSTARTUP`` file if one is
- defined in the environment prior to launching the interpreter.
- See https://github.com/Pylons/pyramid/pull/1448
+ defined in the environment prior to launching the interpreter. See
+ https://github.com/Pylons/pyramid/pull/1448
-- Add new HTTP exception objects for status codes
- ``428 Precondition Required``, ``429 Too Many Requests`` and
- ``431 Request Header Fields Too Large`` in ``pyramid.httpexceptions``.
- See https://github.com/Pylons/pyramid/pull/1372/files
+- Add new HTTP exception objects for status codes ``428 Precondition
+ Required``, ``429 Too Many Requests`` and ``431 Request Header Fields Too
+ Large`` in ``pyramid.httpexceptions``. See
+ https://github.com/Pylons/pyramid/pull/1372/files
- ``pcreate`` when run without a scaffold argument will now print information
- on the missing flag, as well as a list of available scaffolds. See
+ on the missing flag, as well as a list of available scaffolds. See
https://github.com/Pylons/pyramid/pull/1566 and
https://github.com/Pylons/pyramid/issues/1297
+- ``pcreate`` will now ask for confirmation if invoked with an argument for a
+ project name that already exists or is importable in the current environment.
+ See https://github.com/Pylons/pyramid/issues/1357 and
+ https://github.com/Pylons/pyramid/pull/1837
+
- Add :func:`pyramid.request.apply_request_extensions` function which can be
used in testing to apply any request extensions configured via
``config.add_request_method``. Previously it was only possible to test the
- extensions by going through Pyramid's router. See
+ extensions by going through Pyramid's router. See
https://github.com/Pylons/pyramid/pull/1581
-
- Make it possible to subclass ``pyramid.request.Request`` and also use
- ``pyramid.request.Request.add_request.method``. See
+ ``pyramid.request.Request.add_request.method``. See
https://github.com/Pylons/pyramid/issues/1529
+- Additional shells for ``pshell`` can now be registered as entry points. See
+ https://github.com/Pylons/pyramid/pull/1891 and
+ https://github.com/Pylons/pyramid/pull/2012
+
+- The variables injected into ``pshell`` are now displayed with their
+ docstrings instead of the default ``str(obj)`` when possible. See
+ https://github.com/Pylons/pyramid/pull/1929
+
+
Deprecations
------------
+- The ``pserve`` command's daemonization features, as well as
+ ``--monitor-restart``, have been deprecated. This includes the
+ ``[start,stop,restart,status]`` subcommands, as well as the ``--daemon``,
+ ``--stop-daemon``, ``--pid-file``, ``--status``, ``--user``, and ``--group``
+ flags. See https://github.com/Pylons/pyramid/pull/2120 and
+ https://github.com/Pylons/pyramid/pull/2189 and
+ https://github.com/Pylons/pyramid/pull/1641
+
+ Please use a real process manager in the future instead of relying on
+ ``pserve`` to daemonize itself. Many options exist, including your operating
+ system's services, such as Systemd or Upstart, as well as Python-based
+ solutions like Circus and Supervisor.
+
+ See https://github.com/Pylons/pyramid/pull/1641 and
+ https://github.com/Pylons/pyramid/pull/2120
+
- The ``principal`` argument to :func:`pyramid.security.remember` was renamed
- to ``userid``. Using ``principal`` as the argument name still works and will
+ to ``userid``. Using ``principal`` as the argument name still works and will
continue to work for the next few releases, but a deprecation warning is
printed.
@@ -150,21 +202,35 @@ Scaffolding Enhancements
- Added line numbers to the log formatters in the scaffolds to assist with
debugging. See https://github.com/Pylons/pyramid/pull/1326
-- Update scaffold generating machinery to return the version of pyramid and
- pyramid docs for use in scaffolds. Updated ``starter``, ``alchemy`` and
- ``zodb`` templates to have links to correctly versioned documentation and
- reflect which pyramid was used to generate the scaffold.
+- Updated scaffold generating machinery to return the version of :app:`Pyramid`
+ and its documentation for use in scaffolds. Updated ``starter``, ``alchemy``
+ and ``zodb`` templates to have links to correctly versioned documentation,
+ and to reflect which :app:`Pyramid` was used to generate the scaffold.
+
+- Removed non-ASCII copyright symbol from templates, as this was causing the
+ scaffolds to fail for project generation.
-- Removed non-ascii copyright symbol from templates, as this was
- causing the scaffolds to fail for project generation.
Documentation Enhancements
--------------------------
-- Removed logging configuration from Quick Tutorial ini files except for
- scaffolding- and logging-related chapters to avoid needing to explain it too
+- Removed logging configuration from Quick Tutorial ``ini`` files, except for
+ scaffolding- and logging-related chapters, to avoid needing to explain it too
early.
-- Improve and clarify the documentation on what Pyramid defines as a
- ``principal`` and a ``userid`` in its security APIs.
- See https://github.com/Pylons/pyramid/pull/1399
+- Improve and clarify the documentation on what :app:`Pyramid` defines as a
+ ``principal`` and a ``userid`` in its security APIs. See
+ https://github.com/Pylons/pyramid/pull/1399
+
+- Moved the documentation for ``accept`` on
+ :meth:`pyramid.config.Configurator.add_view` to no longer be part of the
+ predicate list. See https://github.com/Pylons/pyramid/issues/1391 for a bug
+ report stating ``not_`` was failing on ``accept``. Discussion with @mcdonc
+ led to the conclusion that it should not be documented as a predicate.
+ See https://github.com/Pylons/pyramid/pull/1487 for this PR.
+
+- Clarify a previously-implied detail of the ``ISession.invalidate`` API
+ documentation.
+
+- Add documentation of command line programs (``p*`` scripts). See
+ https://github.com/Pylons/pyramid/pull/2191