summaryrefslogtreecommitdiff
path: root/docs/narr
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2018-03-13 17:19:44 -0400
committerChris McDonough <chrism@plope.com>2018-03-13 17:19:44 -0400
commitbf59bd87ce2d8dc35f9585087623528bb58363a3 (patch)
treeea5cb12fee6e4453bb8e0bf6b943e1451de7cc73 /docs/narr
parentb2e8884a94d9e869bf29ea55298ad308f16ed420 (diff)
parent47ff29297c65ae2c8da06a5bb2f361f806681ced (diff)
downloadpyramid-bf59bd87ce2d8dc35f9585087623528bb58363a3.tar.gz
pyramid-bf59bd87ce2d8dc35f9585087623528bb58363a3.tar.bz2
pyramid-bf59bd87ce2d8dc35f9585087623528bb58363a3.zip
Merge branch 'master' of github.com:Pylons/pyramid
Diffstat (limited to 'docs/narr')
-rw-r--r--docs/narr/advanced-features.rst330
-rw-r--r--docs/narr/configuration.rst12
-rw-r--r--docs/narr/firstapp.rst20
-rw-r--r--docs/narr/helloworld.py9
-rw-r--r--docs/narr/hooks.rst6
-rw-r--r--docs/narr/i18n.rst6
-rw-r--r--docs/narr/install.rst10
-rw-r--r--docs/narr/introduction.rst984
-rw-r--r--docs/narr/logging.rst42
-rw-r--r--docs/narr/myproject/README.txt2
-rw-r--r--docs/narr/myproject/development.ini6
-rw-r--r--docs/narr/myproject/myproject/templates/layout.jinja212
-rw-r--r--docs/narr/myproject/myproject/templates/mytemplate.jinja22
-rw-r--r--docs/narr/myproject/production.ini4
-rw-r--r--docs/narr/myproject/setup.py1
-rw-r--r--docs/narr/paste.rst14
-rw-r--r--docs/narr/project.rst33
-rw-r--r--docs/narr/scaffolding.rst2
-rw-r--r--docs/narr/security.rst216
-rw-r--r--docs/narr/sessions.rst187
-rw-r--r--docs/narr/startup.rst21
-rw-r--r--docs/narr/subrequest.rst2
-rw-r--r--docs/narr/templates.rst12
-rw-r--r--docs/narr/testing.rst14
-rw-r--r--docs/narr/webob.rst4
25 files changed, 865 insertions, 1086 deletions
diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst
new file mode 100644
index 000000000..82e20963d
--- /dev/null
+++ b/docs/narr/advanced-features.rst
@@ -0,0 +1,330 @@
+Advanced :app:`Pyramid` Design Features
+=======================================
+
+:app:`Pyramid` has been built from the ground up to avoid the problems that other frameworks can suffer.
+
+You Don't Need Singletons
+-------------------------
+
+Have you ever struggled with parameterizing Django's ``settings.py`` file for multiple installations of the same Django application? Have you ever needed to monkey-patch a framework fixture to get it to behave properly for your use case? Have you ever tried to deploy your application using an asynchronous server and failed?
+
+All these problems are symptoms of :term:`mutable` :term:`global state`, also known as :term:`import time` :term:`side effect`\ s and arise from the use of :term:`singleton` data structures.
+
+:app:`Pyramid` is written so that you don't run into these types of problems. It is even possible to run multiple copies of the *same* :app:`Pyramid` application configured differently within a single Python process. This makes running :app:`Pyramid` in shared hosting environments a snap.
+
+Simplify your View Code with Predicates
+---------------------------------------
+
+How many times have you found yourself beginning the logic of your view code with something like this:
+
+.. code-block:: python
+ :linenos:
+
+ if request.user.is_authenticated:
+ # do one thing
+ else:
+ # do something else
+
+Unlike many other systems, :app:`Pyramid` allows you to associate more than one view with a single route. For example, you can create a route with the pattern ``/items`` and when the route is matched, you can send the request to one view if the request method is GET, another view if the request method is POST, and so on.
+
+:app:`Pyramid` uses a system of :term:`view predicate`\ s to allow this. Matching the request method is one basic thing you can do with a :term:`view predicate`. You can also associate views with other request parameters, such as elements in the query string, the Accept header, whether the request is an AJAX (XHR) request or not, and lots of other things.
+
+For our example above, you can do this instead:
+
+.. code-block:: python
+ :linenos:
+
+ @view_config(route_name="items", effective_principals=pyramid.security.Authenticated)
+ def auth_view(request):
+ # do one thing
+
+ @view_config(route_name="items")
+ def anon_view(request):
+ # do something else
+
+This approach allows you to develop view code that is simpler, more easily understandable, and more directly testable.
+
+.. seealso::
+
+ See also :ref:`view_configuration_parameters`.
+
+Stop Worrying About Transactions
+--------------------------------
+
+:app:`Pyramid`\ 's :term:`cookiecutter`\ s render projects that include a *transaction management* system. When you use this system, you can stop worrying about when to commit your changes, :app:`Pyramid` handles it for you. The system will commit at the end of a request or abort if there was an exception.
+
+Why is that a good thing? Imagine a situation where you manually commit a change to your persistence layer. It's very likely that other framework code will run *after* your changes are done. If an error happens in that other code, you can easily wind up with inconsistent data if you're not extremely careful.
+
+Using transaction management saves you from needing to think about this. Either a request completes successfully and all changes are committed, or it does not and all changes are aborted.
+
+:app:`Pyramid`\ 's transaction management is extendable, so you can synchronize commits between multiple databases or databases of different kinds. It also allows you to do things like conditionally send email if a transaction is committed, but otherwise keep quiet.
+
+.. seealso::
+
+ See also :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements anywhere in application code).
+
+Stop Worrying About Configuration
+---------------------------------
+
+When a system is small, it's reasonably easy to keep it all in your head. But as systems grow large, configuration grows more complex. Your app may grow to have hundreds or even thousands of configuration statements.
+
+:app:`Pyramid`\ 's configuration system keeps track of each of your statements. If you accidentally add two that are identical, or :app:`Pyramid` can't make sense out of what it would mean to have both statements active at the same time, it will complain loudly at startup time.
+
+:app:`Pyramid`\ 's configuration system is not dumb though. If you use the :meth:`~pyramid.config.Configurator.include` system, it can automatically resolve conflicts on its own. More local statements are preferred over less local ones. So you can intelligently factor large systems into smaller ones.
+
+.. seealso::
+
+ See also :ref:`conflict_detection`.
+
+Compose Powerful Apps From Simple Parts
+----------------------------------------
+
+Speaking of the :app:`Pyramid` structured :meth:`~pyramid.config.Configurator.include` mechanism, it allows you to compose complex applications from multiple, simple Python packages. All the configuration statements that can be performed in your main :app:`Pyramid` application can also be used in included packages. You can add views, routes, and subscribers, and even set authentication and authorization policies.
+
+If you need, you can extend or override the configuration of an existing application by including its configuration in your own and then modifying it.
+
+
+For example, if you want to reuse an existing application that already has a bunch of routes, you can just use the ``include`` statement with a ``route_prefix``. All the routes of that application will be availabe, prefixed as you requested:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.include('pyramid_jinja2')
+ config.include('pyramid_exclog')
+ config.include('some.other.package', route_prefix='/somethingelse')
+
+.. seealso::
+
+ See also :ref:`including_configuration` and :ref:`building_an_extensible_app`.
+
+Authenticate Users Your Way
+---------------------------
+
+:app:`Pyramid` ships with prebuilt, well-tested authentication and authorization schemes out of the box. Using a scheme is a matter of configuration. So if you need to change approaches later, you need only update your configuration.
+
+In addition, the system that handles authentication and authorization is flexible and pluggable. If you want to use another security add-on, or define your own, you can. And again, you need only update your application configuration to make the change.
+
+.. seealso::
+
+ See also :ref:`enabling_authorization_policy`.
+
+Build Trees of Resources
+------------------------
+
+:app:`Pyramid` supports :term:`traversal`, a way of mapping URLs to a concrete :term:`resource tree`. If your application naturally consists of an arbitrary heirarchy of different types of content (like a CMS or a Document Management System), traversal is for you. If you have a requirement for a highly granular security model ("Jane can edit documents in *this* folder, but not *that* one"), traversal can be a powerful approach.
+
+.. seealso::
+
+ See also :ref:`hello_traversal_chapter` and :ref:`much_ado_about_traversal_chapter`.
+
+Take Action on Each Request with Tweens
+---------------------------------------
+
+:app:`Pyramid` has a system for applying an arbitrary action to each request or response called a :term:`tween`. The system is similar in concept to WSGI :term:`middleware`, but can be more useful since :term:`tween`\ s run in the :app:`Pyramid` context, and have access to templates, request objects, and other niceties.
+
+The :app:`Pyramid` debug toolbar is a :term:`tween`, as is the ``pyramid_tm`` transaction manager.
+
+.. seealso::
+
+ See also :ref:`registering_tweens`.
+
+Return What You Want From Your Views
+------------------------------------
+
+We have shown elsewhere (in the :doc:`introduction`) how using a :term:`renderer` allows you to return simple Python dictionaries from your view code. But some frameworks allow you to return strings or tuples from view callables. When frameworks allow for this, code looks slightly prettier because there are fewer imports and less code. For example, compare this:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+
+ def aview(request):
+ return Response("Hello world!")
+
+To this:
+
+.. code-block:: python
+ :linenos:
+
+ def aview(request):
+ return "Hello world!"
+
+Nicer to look at, right?
+
+Out of the box, :app:`Pyramid` will raise an exception if you try to run the second example above. After all, a view should return a response, and "explicit is better than implicit".
+
+But if you're a developer who likes the aesthetics of simplicity, :app:`Pyramid` provides a way to support this sort of thing, the :term:`response adapter`\ :
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+ from pyramid.response import Response
+
+ def string_response_adapter(s):
+ response = Response(s)
+ response.content_type = 'text/html'
+ return response
+
+A new response adapter is registered in configuration:
+
+.. code-block:: python
+ :linenos:
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_response_adapter(string_response_adapter, str)
+
+With that, you may return strings from any of your view callables, e.g.:
+
+.. code-block:: python
+ :linenos:
+
+ def helloview(request):
+ return "Hello world!"
+
+ def goodbyeview(request):
+ return "Goodbye world!"
+
+You can even use a :term:`response adapter` to allow for custom content types and return codes:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ def tuple_response_adapter(val):
+ status_int, content_type, body = val
+ response = Response(body)
+ response.content_type = content_type
+ response.status_int = status_int
+ return response
+
+ def string_response_adapter(body):
+ response = Response(body)
+ response.content_type = 'text/html'
+ response.status_int = 200
+ return response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_response_adapter(string_response_adapter, str)
+ config.add_response_adapter(tuple_response_adapter, tuple)
+
+With this, both of these views will work as expected:
+
+.. code-block:: python
+ :linenos:
+
+ def aview(request):
+ return "Hello world!"
+
+ def anotherview(request):
+ return (403, 'text/plain', "Forbidden")
+
+.. seealso::
+
+ See also :ref:`using_iresponse`.
+
+Use Global Response Objects
+---------------------------
+
+Views have to return responses. But constructing them in view code is a chore. And perhaps registering a :term:`response adapter` as shown above is just too much work. :app:`Pyramid` provides a global response object as well. You can use it directly, if you prefer:
+
+.. code-block:: python
+ :linenos:
+
+ def aview(request):
+ response = request.response
+ response.body = 'Hello world!'
+ response.content_type = 'text/plain'
+ return response
+
+.. seealso::
+
+ See also :ref:`request_response_attr`.
+
+Extend Configuration
+--------------------
+
+Perhaps the :app:`Pyramid` configurator's syntax feels a bit verbose to you. Or possibly you would like to add a feature to configuration without asking the core developers to change :app:`Pyramid` itself?
+
+You can extend :app:`Pyramid`\ 's :term:`configurator` with your own directives. For example, let's say you find yourself calling :meth:`pyramid.config.Configurator.add_view` repetitively. Usually you can get rid of the boring with existing shortcuts, but let's say that this is a case where there is no such shortcut:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ config.add_route('xhr_route', '/xhr/{id}')
+ config.add_view('my.package.GET_view', route_name='xhr_route',
+ xhr=True, permission='view', request_method='GET')
+ config.add_view('my.package.POST_view', route_name='xhr_route',
+ xhr=True, permission='view', request_method='POST')
+ config.add_view('my.package.HEAD_view', route_name='xhr_route',
+ xhr=True, permission='view', request_method='HEAD')
+
+Pretty tedious right? You can add a directive to the :app:`Pyramid` :term:`configurator` to automate some of the tedium away:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+
+ def add_protected_xhr_views(config, module):
+ module = config.maybe_dotted(module)
+ for method in ('GET', 'POST', 'HEAD'):
+ view = getattr(module, 'xhr_%s_view' % method, None)
+ if view is not None:
+ config.add_view(view, route_name='xhr_route', xhr=True,
+ permission='view', request_method=method)
+
+ config = Configurator()
+ config.add_directive('add_protected_xhr_views', add_protected_xhr_views)
+
+Once that's done, you can call the directive you've just added as a method of the :term:`configurator` object:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_route('xhr_route', '/xhr/{id}')
+ config.add_protected_xhr_views('my.package')
+
+Much better!
+
+You can share your configuration code with others, too. Add your code to a Python package. Put the call to :meth:`~pyramid.config.Configurator.add_directive` in a function. When other programmers install your package, they'll be able to use your configuration by passing your function to a call to :meth:`~pyramid.config.Configurator.include`.
+
+.. seealso::
+
+ See also :ref:`add_directive`.
+
+Introspect Your Application
+---------------------------
+
+If you're building a large, pluggable system, it's useful to be able to get a list of what has been plugged in *at application runtime*. For example, you might want to show users a set of tabs at the top of the screen based on a list of the views they registered.
+
+:app:`Pyramid` provides an :term:`introspector` for just this purpose.
+
+Here's an example of using :app:`Pyramid`\ 's :term:`introspector` from within a view:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(route_name='bar')
+ def show_current_route_pattern(request):
+ introspector = request.registry.introspector
+ route_name = request.matched_route.name
+ route_intr = introspector.get('routes', route_name)
+ return Response(str(route_intr['pattern']))
+
+.. seealso::
+
+ See also :ref:`using_introspection`. \ No newline at end of file
diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst
index ee54e3acd..bbf01240e 100644
--- a/docs/narr/configuration.rst
+++ b/docs/narr/configuration.rst
@@ -47,9 +47,9 @@ configured imperatively:
return Response('Hello world!')
if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- app = config.make_wsgi_app()
+ with Configurator() as config:
+ config.add_view(hello_world)
+ app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
@@ -116,9 +116,9 @@ and its subpackages. For example:
return Response('Hello')
if __name__ == '__main__':
- config = Configurator()
- config.scan()
- app = config.make_wsgi_app()
+ with Configurator() as config:
+ config.scan()
+ app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst
index ad05976c0..db55f2f9c 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -60,7 +60,7 @@ Imports
The above ``helloworld.py`` script uses the following set of import statements:
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:lines: 1-3
The script imports the :class:`~pyramid.config.Configurator` class from the
@@ -83,7 +83,7 @@ The above script, beneath its set of imports, defines a function named
``hello_world``.
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:pyobject: hello_world
The function accepts a single argument (``request``) and it returns an instance
@@ -125,7 +125,7 @@ imports and function definitions, placed within the confines of an ``if``
statement:
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:lines: 9-15
Let's break this down piece by piece.
@@ -134,7 +134,7 @@ Configurator Construction
~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:lines: 9-10
The ``if __name__ == '__main__':`` line in the code sample above represents a
@@ -153,8 +153,8 @@ code within the ``if`` statement to execute if this module is imported from
another; the code within the ``if`` block should only be run during a direct
script execution.
-The ``config = Configurator()`` line above creates an instance of the
-:class:`~pyramid.config.Configurator` class. The resulting ``config`` object
+The ``with Configurator() as config:`` line above creates an instance of the
+:class:`~pyramid.config.Configurator` class using a :term:`context manager`. The resulting ``config`` object
represents an API which the script uses to configure this particular
:app:`Pyramid` application. Methods called on the Configurator will cause
registrations to be made in an :term:`application registry` associated with the
@@ -166,7 +166,7 @@ Adding Configuration
~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:lines: 11-12
The first line above calls the :meth:`pyramid.config.Configurator.add_route`
@@ -185,7 +185,7 @@ WSGI Application Creation
~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:lines: 13
After configuring views and ending configuration, the script creates a WSGI
@@ -197,7 +197,7 @@ method returns a :term:`WSGI` application object that can be used by any WSGI
server to present an application to a requestor. :term:`WSGI` is a protocol
that allows servers to talk to Python applications. We don't discuss
:term:`WSGI` in any depth within this book, but you can learn more about it by
-reading its `documentation <http://wsgi.readthedocs.org/en/latest/>`_.
+reading its `documentation <https://wsgi.readthedocs.io/en/latest/>`_.
The :app:`Pyramid` application object, in particular, is an instance of a class
representing a :app:`Pyramid` :term:`router`. It has a reference to the
@@ -212,7 +212,7 @@ WSGI Application Serving
~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: helloworld.py
- :linenos:
+ :lineno-match:
:lines: 14-15
Finally, we actually serve the application to requestors by starting up a WSGI
diff --git a/docs/narr/helloworld.py b/docs/narr/helloworld.py
index c01329af9..29ed8e6f2 100644
--- a/docs/narr/helloworld.py
+++ b/docs/narr/helloworld.py
@@ -7,10 +7,9 @@ def hello_world(request):
return Response('Hello %(name)s!' % request.matchdict)
if __name__ == '__main__':
- config = Configurator()
- config.add_route('hello', '/hello/{name}')
- config.add_view(hello_world, route_name='hello')
- app = config.make_wsgi_app()
+ with Configurator() as config:
+ config.add_route('hello', '/hello/{name}')
+ config.add_view(hello_world, route_name='hello')
+ app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 63279027a..f9bb72986 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -1059,8 +1059,8 @@ enabling you to set up the utility in advance:
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
-For full details, please read the `Venusian documentation
-<http://docs.repoze.org/venusian>`_.
+For full details, please read the :ref:`Venusian documentation <venusian:venusian>`.
+
.. _registering_tweens:
@@ -1569,7 +1569,7 @@ event type.
def __call__(self, event):
return event.request.path.startswith(self.val)
-Once you've created a subscriber predicate, it may registered via
+Once you've created a subscriber predicate, it may be registered via
:meth:`pyramid.config.Configurator.add_subscriber_predicate`. For example:
.. code-block:: python
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index 3549b53a5..e64584322 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -647,7 +647,7 @@ before being rendered:
The features represented by attributes of the ``i18n`` namespace of Chameleon
will also consult the :app:`Pyramid` translations. See
-http://chameleon.readthedocs.org/en/latest/reference.html#translation-i18n.
+https://chameleon.readthedocs.io/en/latest/reference.html#translation-i18n.
.. note::
@@ -681,9 +681,9 @@ Jinja2 Pyramid i18n Support
The add-on `pyramid_jinja2 <https://github.com/Pylons/pyramid_jinja2>`_
provides a scaffold with an example of how to use internationalization with
Jinja2 in Pyramid. See the documentation sections `Internalization (i18n)
-<http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/#internalization-i18n>`_
+<https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/#internalization-i18n>`_
and `Paster Template I18N
-<http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/#paster-template-i18n>`_.
+<https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/#paster-template-i18n>`_.
.. index::
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index 2a25ad84d..a9ec68d61 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -51,10 +51,10 @@ Python comes pre-installed on Mac OS X, but due to Apple's release cycle, it is
often out of date. Unless you have a need for a specific earlier version, it is
recommended to install the latest 3.x version of Python.
-You can install the latest verion of Python for Mac OS X from the binaries on
+You can install the latest version of Python for Mac OS X from the binaries on
`python.org <https://www.python.org/downloads/mac-osx/>`_.
-Alternatively, you can use the `homebrew <http://brew.sh/>`_ package manager.
+Alternatively, you can use the `homebrew <https://brew.sh/>`_ package manager.
.. code-block:: text
@@ -157,7 +157,7 @@ application, rather than being installed system wide.
.. seealso:: See the Python Packaging Authority's (PyPA) documention
`Requirements for Installing Packages
- <https://packaging.python.org/en/latest/installing/#requirements-for-installing-packages>`_
+ <https://packaging.python.org/tutorials/installing-packages/#requirements-for-installing-packages>`_
for full details.
@@ -206,9 +206,7 @@ After installing Python as described previously in :ref:`for-mac-os-x-users` or
``$VENV/bin/pip`` clearly specifies that ``pip`` is run from within the
virtual environment and not at the system level.
- ``activate`` drops turds into the user's shell environment, leaving them
- vulnerable to executing commands in the wrong context. ``deactivate`` might
- not correctly restore previous shell environment variables.
+ ``activate`` makes changes to the user's shell environment which can often be convenient. However, in the context of long-form documentation, environment configuration can easily be forgotten. By keeping each snippet explicit we can reduce copy / paste errors by users in which commands are executed against the wrong Python environment. Also, ``deactivate`` might not correctly restore previous shell environment variables. Avoiding ``activate`` keeps the environment more reproducible.
Although using ``source bin/activate``, then ``pip``, requires fewer key
strokes to issue commands once invoked, there are other things to consider.
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index 3aa603bcf..df3567726 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -9,112 +9,87 @@
:app:`Pyramid` Introduction
===========================
-:app:`Pyramid` is a general, open source, Python web application development
-*framework*. Its primary goal is to make it easier for a Python developer to
-create web applications.
-
-.. sidebar:: Frameworks vs. Libraries
-
- A *framework* differs from a *library* in one very important way: library
- code is always *called* by code that you write, while a framework always
- *calls* code that you write. Using a set of libraries to create an
- application is usually easier than using a framework initially, because you
- can choose to cede control to library code you have not authored very
- selectively. But when you use a framework, you are required to cede a
- greater portion of control to code you have not authored: code that resides
- in the framework itself. You needn't use a framework at all to create a web
- application using Python. A rich set of libraries already exists for the
- platform. In practice, however, using a framework to create an application
- is often more practical than rolling your own via a set of libraries if the
- framework provides a set of facilities that fits your application
- requirements.
-
-Pyramid attempts to follow these design and engineering principles:
+:app:`Pyramid` is a Python web application *framework*. It is designed to make creating web applications easier. It is open source.
+
+.. sidebar:: What Is a Framework?
+
+ A *framework* provides capabilities that developers can enhance or extend. A web application framework provides many of the common needs of building web applications allowing developers to concentrate only on the parts that are specific to their application.
+
+ Every framework makes choices about how a particular problem should be solved. When developers choose to use a framework, they cede control over the portions of their application that are provided by the framework. It is possible to write a complete web application without any framework, by using Python libraries. In practice, however, it is often more practical to use a framework, so long as your chosen framework fits the requirements of your application.
+
+:app:`Pyramid` follows these design and engineering principles:
Simplicity
- :app:`Pyramid` takes a *"pay only for what you eat"* approach. You can get
- results even if you have only a partial understanding of :app:`Pyramid`. It
- doesn't force you to use any particular technology to produce an application,
- and we try to keep the core set of concepts that you need to understand to a
- minimum.
+ :app:`Pyramid` is designed to be easy to use. You can get started even if you don't understand it all. And when you're ready to do more, :app:`Pyramid` will be there for you.
Minimalism
- :app:`Pyramid` tries to solve only the fundamental problems of creating a web
- application: the mapping of URLs to code, templating, security, and serving
- static assets. We consider these to be the core activities that are common to
- nearly all web applications.
+ Out of the box, :app:`Pyramid` provides only the core tools needed for nearly all web applications: mapping URLs to code, security, and serving static assets (files like JavaScript and CSS). Additional tools provide templating, database integration and more. But with :app:`Pyramid` you can *"pay only for what you eat"*.
Documentation
- Pyramid's minimalism means that it is easier for us to maintain complete and
- up-to-date documentation. It is our goal that no aspect of Pyramid is
- undocumented.
+ :app:`Pyramid` is committed to comprehensive and up-to-date documentation.
Speed
- :app:`Pyramid` is designed to provide noticeably fast execution for common
- tasks such as templating and simple response generation.
+ :app:`Pyramid` is designed to be noticeably fast.
Reliability
- :app:`Pyramid` is developed conservatively and tested exhaustively. Where
- Pyramid source code is concerned, our motto is: "If it ain't tested, it's
- broke".
+ :app:`Pyramid` is developed conservatively and tested exhaustively. Our motto is: "If it ain't tested, it's broke".
Openness
- As with Python, the Pyramid software is distributed under a `permissive open
- source license <http://repoze.org/license.html>`_.
+ As with Python, the :app:`Pyramid` software is distributed under a `permissive open source license <http://repoze.org/license.html>`_.
+
+.. _why_pyramid:
+
+Why Pyramid?
+------------
+
+In a world filled with web frameworks, why should you choose :app:`Pyramid`\ ?
+
+Modern
+~~~~~~
+
+:app:`Pyramid` is fully compatible with Python 3. If you develop a :app:`Pyramid` application today, you can rest assured that you'll be able to use the most modern features of your favorite language. And in the years to come, you'll continue to bed working on a framework that is up-to-date and forward-looking.
+
+Tested
+~~~~~~
+
+Untested code is broken by design. The :app:`Pyramid` community has a strong testing culture and our framework reflects that. Every release of :app:`Pyramid` has 100% statement coverage (as measured by `coverage <http://coverage.readthedocs.io/en/latest/>`_) and 95% decision/condition coverage. (as measured by `instrumental <http://instrumental.readthedocs.io/en/latest/intro.html>`_) It is automatically tested using `Travis <https://travis-ci.org/Pylons/pyramid>`_ and `Jenkins <http://jenkins.pylonsproject.org/job/pyramid/>`_ on supported versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons <https://trypyramid.com/resources-extending-pyramid.html>`_ are held to a similar testing standard.
+
+We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of them while working on projects with a solid testing regime.
+
+Documented
+~~~~~~~~~~
+
+The :app:`Pyramid` documentation is comprehensive. We strive to keep our narrative documentation both complete and friendly to newcomers. We also maintain the :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>` of recipes demonstrating common scenarios you might face. Contributions in the form of improvements to our documentation are always appreciated. And we always welcome improvements to our `official tutorials <html_tutorials>`_ as well as new contributions to our `community maintained tutorials <tutorials:pyramid-tutorials>`_.
+
+Supported
+~~~~~~~~~
+
+You can get help quickly with :app:`Pyramid`. It's our goal that no :app:`Pyramid` question go unanswered. Whether you ask a question on IRC, on the Pylons-discuss mailing list, or on StackOverflow, you're likely to get a reasonably prompt response.
+
+:app:`Pyramid` is also a welcoming, friendly space for newcomers. We don't tolerate "support trolls" or those who enjoy berating fellow users in our support channels. We try to keep it well-lit and new-user-friendly.
+
+.. seealso::
+
+ See also our `#pyramid IRC channel <https://webchat.freenode.net/?channels=pyramid>`_, our `pylons-discuss mailing list <https://groups.google.com/forum/#!forum/pylons-discuss>`_, and :ref:`support-and-development`.
.. _what_makes_pyramid_unique:
What makes Pyramid unique
-------------------------
-Understandably, people don't usually want to hear about squishy engineering
-principles; they want to hear about concrete stuff that solves their problems.
-With that in mind, what would make someone want to use Pyramid instead of one
-of the many other web frameworks available today? What makes Pyramid unique?
-
-This is a hard question to answer because there are lots of excellent choices,
-and it's actually quite hard to make a wrong choice, particularly in the Python
-web framework market. But one reasonable answer is this: you can write very
-small applications in Pyramid without needing to know a lot. "What?" you say.
-"That can't possibly be a unique feature. Lots of other web frameworks let you
-do that!" Well, you're right. But unlike many other systems, you can also
-write very large applications in Pyramid if you learn a little more about it.
-Pyramid will allow you to become productive quickly, and will grow with you. It
-won't hold you back when your application is small, and it won't get in your
-way when your application becomes large. "Well that's fine," you say. "Lots of
-other frameworks let me write large apps, too." Absolutely. But other Python
-web frameworks don't seamlessly let you do both. They seem to fall into two
-non-overlapping categories: frameworks for "small apps" and frameworks for "big
-apps". The "small app" frameworks typically sacrifice "big app" features, and
-vice versa.
-
-We don't think it's a universally reasonable suggestion to write "small apps"
-in a "small framework" and "big apps" in a "big framework". You can't really
-know to what size every application will eventually grow. We don't really want
-to have to rewrite a previously small application in another framework when it
-gets "too big". We believe the current binary distinction between frameworks
-for small and large applications is just false. A well-designed framework
-should be able to be good at both. Pyramid strives to be that kind of
-framework.
-
-To this end, Pyramid provides a set of features that combined are unique
-amongst Python web frameworks. Lots of other frameworks contain some
-combination of these features. Pyramid of course actually stole many of them
-from those other frameworks. But Pyramid is the only one that has all of them
-in one place, documented appropriately, and useful *à la carte* without
-necessarily paying for the entire banquet. These are detailed below.
-
-Single-file applications
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can write a Pyramid application that lives entirely in one Python file, not
-unlike existing Python microframeworks. This is beneficial for one-off
-prototyping, bug reproduction, and very small applications. These applications
-are easy to understand because all the information about the application lives
-in a single place, and you can deploy them without needing to understand much
-about Python distributions and packaging. Pyramid isn't really marketed as a
-microframework, but it allows you to do almost everything that frameworks that
-are marketed as "micro" offer in very similar ways.
+There are many tools available for web development. What would make someone want to use :app:`Pyramid` instead? What makes :app:`Pyramid` unique?
+
+With :app:`Pyramid` you can write very small applications without needing to know a lot. And by learning a bit more, you can write very large applications too. :app:`Pyramid` will allow you to become productive quickly, and will grow with you. It won't hold you back when your application is small, and it won't get in your way when your application becomes large. Other application frameworks seem to fall into two non-overlapping categories: those that support "small apps" and those designed for "big apps".
+
+We don't believe you should have to make this choice. You can't really know how large your application will become. You certainly shouldn't have to rewrite a small application in another framework when it gets "too big". A well-designed framework should be able to be good at both. :app:`Pyramid` is that kind of framework.
+
+:app:`Pyramid` provides a set of features that are unique among Python web frameworks. Others may provide some, but only :app:`Pyramid` provides them all, in one place, fully documented, and *à la carte* without needing to pay for the whole banquet.
+
+
+Build single-file applications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can write a :app:`Pyramid` application that lives entirely in one Python file. Such an application is easy to understand since everything is in one place. It is easy to deploy because you don't need to know much about Python packaging. :app:`Pyramid` allows you to do almost everything that so-called *microframeworks* can in very similar ways.
.. literalinclude:: helloworld.py
@@ -122,13 +97,10 @@ are marketed as "micro" offer in very similar ways.
See also :ref:`firstapp_chapter`.
-Decorator-based configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Configure applications with decorators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you like the idea of framework configuration statements living next to the
-code it configures, so you don't have to constantly switch between files to
-refer to framework configuration when adding new code, you can use Pyramid
-decorators to localize the configuration. For example:
+:app:`Pyramid` allows you to keep your configuration right next to your code. That way you don't have to switch files to see your configuration. For example:
.. code-block:: python
@@ -139,103 +111,74 @@ decorators to localize the configuration. For example:
def fred_view(request):
return Response('fred')
-However, unlike some other systems, using decorators for Pyramid configuration
-does not make your application difficult to extend, test, or reuse. The
-:class:`~pyramid.view.view_config` decorator, for example, does not actually
-*change* the input or output of the function it decorates, so testing it is a
-"WYSIWYG" operation. You don't need to understand the framework to test your
-own code. You just behave as if the decorator is not there. You can also
-instruct Pyramid to ignore some decorators, or use completely imperative
-configuration instead of decorators to add views. Pyramid decorators are inert
-instead of eager. You detect and activate them with a :term:`scan`.
+However, using :app:`Pyramid` configuration decorators does not change your code. It remains easy to extend, test, or reuse. You can test your code as if the decorators were not there. You can instruct the framework to ignore some decorators. You can even use an imperative style to write your configuration, skipping decorators entirely.
-Example: :ref:`mapping_views_using_a_decorator_section`.
+.. seealso::
+
+ See also :ref:`mapping_views_using_a_decorator_section`.
+
+Generate application URLs
+~~~~~~~~~~~~~~~~~~~~~~~~~
-URL generation
-~~~~~~~~~~~~~~
+Dynamic web applications produce URLs that can change depending on what you are viewing. :app:`Pyramid` provides flexible, consistent, easy to use tools for generating URLs. When you use these tools to write your application, you can change your configuration without fear of breaking links in your web pages.
-Pyramid is capable of generating URLs for resources, routes, and static assets.
-Its URL generation APIs are easy to use and flexible. If you use Pyramid's
-various APIs for generating URLs, you can change your configuration around
-arbitrarily without fear of breaking a link on one of your web pages.
+.. seealso::
-Example: :ref:`generating_route_urls`.
+ See also :ref:`generating_route_urls`.
-Static file serving
+Serve static assets
~~~~~~~~~~~~~~~~~~~
-Pyramid is perfectly willing to serve static files itself. It won't make you
-use some external web server to do that. You can even serve more than one set
-of static files in a single Pyramid web application (e.g., ``/static`` and
-``/static2``). You can optionally place your files on an external web server
-and ask Pyramid to help you generate URLs to those files. This let's you use
-Pyramid's internal file serving while doing development, and a faster static
-file server in production, without changing any code.
+Web applications often require JavaScript, CSS, images and other so-called *static assets*. :app:`Pyramid` provides flexible tools for serving these kinds of files. You can serve them directly from :app:`Pyramid`, or host them on an external server or CDN (content delivery network). Either way, :app:`Pyramid` can help you to generate URLs so you can change where your files come from without changing any code.
-Example: :ref:`static_assets_section`.
+.. seealso::
-Fully interactive development
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ See also :ref:`static_assets_section`.
-When developing a Pyramid application, several interactive features are
-available. Pyramid can automatically utilize changed templates when rendering
-pages and automatically restart the application to incorporate changed Python
-code. Plain old ``print()`` calls used for debugging can display to a console.
+Develop interactively
+~~~~~~~~~~~~~~~~~~~~~
-Pyramid's debug toolbar comes activated when you use a Pyramid :term:`cookiecutter` to
-render a project. This toolbar overlays your application in the browser, and
-allows you access to framework data, such as the routes configured, the last
-renderings performed, the current set of packages installed, SQLAlchemy queries
-run, logging data, and various other facts. When an exception occurs, you can
-use its interactive debugger to poke around right in your browser to try to
-determine the cause of the exception. It's handy.
+:app:`Pyramid` can automatically detect changes you make to template files and code, so your changes are immediately available in your browser. You can debug using plain old ``print()`` calls, which will display to your console.
-Example: :ref:`debug_toolbar`.
+:app:`Pyramid` has a debug toolbar that allows you to see information about how your application is working right in your browser. See configuration, installed packages, SQL queries, logging statements and more.
-Debugging settings
-~~~~~~~~~~~~~~~~~~
+When your application has an error, an interactive debugger allows you to poke around from your browser to find out what happened.
+
+To use the :app:`Pyramid` debug toolbar, build your project with a :app:`Pyramid` :term:`cookiecutter`.
+
+.. seealso::
+
+ See also :ref:`debug_toolbar`.
+
+Debug with power
+~~~~~~~~~~~~~~~~
+
+When things go wrong, :app:`Pyramid` gives you powerful ways to fix the problem.
+
+You can configure :app:`Pyramid` to print helpful information to the console. The ``debug_notfound`` setting shows information about URLs that aren't matched. The ``debug_authorization`` setting provides helpful messages about why you aren't allowed to do what you just tried.
+
+:app:`Pyramid` also has command line tools to help you verify your configuration. You can use ``proutes`` and ``pviews`` to inspect how URLs are connected to your application code.
+
+.. seealso::
-Pyramid has debugging settings that allow you to print Pyramid runtime
-information to the console when things aren't behaving as you're expecting. For
-example, you can turn on ``debug_notfound``, which prints an informative
-message to the console every time a URL does not match any view. You can turn
-on ``debug_authorization``, which lets you know why a view execution was
-allowed or denied by printing a message to the console. These features are
-useful for those WTF moments.
-
-There are also a number of commands that you can invoke within a Pyramid
-environment that allow you to introspect the configuration of your system.
-``proutes`` shows all configured routes for an application in the order they'll
-be evaluated for matching. ``pviews`` shows all configured views for any given
-URL. These are also WTF-crushers in some circumstances.
-
-Examples: :ref:`debug_authorization_section` and :ref:`command_line_chapter`.
-
-Add-ons
-~~~~~~~
-
-Pyramid has an extensive set of add-ons held to the same quality standards as
-the Pyramid core itself. Add-ons are packages which provide functionality that
-the Pyramid core doesn't. Add-on packages already exist which let you easily
-send email, let you use the Jinja2 templating system, let you use XML-RPC or
-JSON-RPC, let you integrate with jQuery Mobile, etc.
-
-Examples:
-https://trypyramid.com/resources-extending-pyramid.html
-
-Class-based and function-based views
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Pyramid has a structured, unified concept of a :term:`view callable`. View
-callables can be functions, methods of classes, or even instances. When you
-add a new view callable, you can choose to make it a function or a method of a
-class. In either case Pyramid treats it largely the same way. You can change
-your mind later and move code between methods of classes and functions. A
-collection of similar view callables can be attached to a single class as
-methods, if that floats your boat, and they can share initialization code as
-necessary. All kinds of views are easy to understand and use, and operate
-similarly. There is no phony distinction between them. They can be used for
-the same purposes.
+ See also :ref:`debug_authorization_section`, :ref:`command_line_chapter`,
+ and :doc:`../pscripts/index`
+
+Extend your application
+~~~~~~~~~~~~~~~~~~~~~~~
+
+:app:`Pyramid` add-ons extend the core of the framework with useful abilities. There are add-ons available for your favorite template language, SQL and NoSQL databases, authentication services and more.
+
+Supported :app:`Pyramid` add-ons are held to the same demanding standards as the framework itself. You will find them to be fully tested and well documented.
+
+.. seealso::
+
+ See also https://trypyramid.com/resources-extending-pyramid.html
+
+Write your views, *your* way
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A fundamental task for any framework is to map URLs to code. In :app:`Pyramid`, that code is called a :term:`view callable`. View callables can be functions, class methods or even callable class instances. You are free to choose the approach that best fits your use case. Regardless of your choice, :app:`Pyramid` treats them the same. You can change your mind at any time without any penalty. There are no artificial distinctions between the various approaches.
Here's a view callable defined as a function:
@@ -275,54 +218,30 @@ Here's a few views defined as methods of a class instead:
.. _intro_asset_specs:
-Asset specifications
-~~~~~~~~~~~~~~~~~~~~
+Find *your* static assets
+~~~~~~~~~~~~~~~~~~~~~~~~~
-Asset specifications are strings that contain both a Python package name and a
-file or directory name, e.g., ``MyPackage:static/index.html``. Use of these
-specifications is omnipresent in Pyramid. An asset specification can refer to
-a template, a translation directory, or any other package-bound static
-resource. This makes a system built on Pyramid extensible because you don't
-have to rely on globals ("*the* static directory") or lookup schemes ("*the*
-ordered set of template directories") to address your files. You can move
-files around as necessary, and include other packages that may not share your
-system's templates or static files without encountering conflicts.
-
-Because asset specifications are used heavily in Pyramid, we've also provided a
-way to allow users to override assets. Say you love a system that someone else
-has created with Pyramid but you just need to change "that one template" to
-make it all better. No need to fork the application. Just override the asset
-specification for that template with your own inside a wrapper, and you're good
-to go.
+In many web frameworks, the static assets required by an application are kept in a globally shared location, "the *static* directory". Others use a lookup scheme, like an ordered set of template directories. Both of these approaches have problems when it comes to customization.
+
+:app:`Pyramid` takes a different approach. Static assets are located using *asset specifications*, strings that contain reference both to a Python package name and a file or directory name, e.g. ``MyPackage:static/index.html``. These specifications are used for templates, JavaScript and CSS, translation files, and any other package-bound static resource. By using asset specifications, :app:`Pyramid` makes it easy to extend your application with other packages without worrying about conflicts.
+
+What happens if another :app:`Pyramid` package you are using provides an asset you need to customize? Maybe that page template needs better HTML, or you want to update some CSS. With asset specifications you can override the assets from other packages using simple wrappers.
Examples: :ref:`asset_specifications` and :ref:`overriding_assets_section`.
-Extensible templating
-~~~~~~~~~~~~~~~~~~~~~
+Use *your* templates
+~~~~~~~~~~~~~~~~~~~~
-Pyramid has a structured API that allows for pluggability of "renderers".
-Templating systems such as Mako, Genshi, Chameleon, and Jinja2 can be treated
-as renderers. Renderer bindings for all of these templating systems already
-exist for use in Pyramid. But if you'd rather use another, it's not a big
-deal. Just copy the code from an existing renderer package, and plug in your
-favorite templating system. You'll then be able to use that templating system
-from within Pyramid just as you'd use one of the "built-in" templating systems.
+In :app:`Pyramid`, the job of creating a ``Response`` belongs to a :term:`renderer`. Any templating system—Mako, Chameleon, Jinja2—can be a renderer. In fact, packages exist for all of these systems. But if you'd rather use another, a structured API exists allowing you to create a renderer using your favorite templating system. You can use the templating system *you* understand, not one required by the framework.
-Pyramid does not make you use a single templating system exclusively. You can
-use multiple templating systems, even in the same project.
+What's more, :app:`Pyramid` does not make you use a single templating system exclusively. You can use multiple templating systems, even in the same project.
Example: :ref:`templates_used_directly`.
-Rendered views can return dictionaries
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Write testable views
+~~~~~~~~~~~~~~~~~~~~
-If you use a :term:`renderer`, you don't have to return a special kind of
-"webby" ``Response`` object from a view. Instead you can return a dictionary,
-and Pyramid will take care of converting that dictionary to a Response using a
-template on your behalf. This makes the view easier to test, because you don't
-have to parse HTML in your tests. Instead just make an assertion that the view
-returns "the right stuff" in the dictionary. You can write "real" unit tests
-instead of functionally testing all of your views.
+When you use a :term:`renderer` with your view callable, you are freed from needing to return a "webby" ``Response`` object. Instead your views can return a simple Python dictionary. :app:`Pyramid` will take care of rendering the information in that dictionary to a ``Response`` on your behalf. As a result, your views are more easily tested, since you don't need to parse HTML to evaluate the results. :app:`Pyramid` makes it a snap to write unit tests for your views, instead of requiring you to use functional tests.
.. index::
pair: renderer; explicitly calling
@@ -330,8 +249,7 @@ instead of functionally testing all of your views.
.. _example_render_to_response_call:
-For example, instead of returning a ``Response`` object from a
-``render_to_response`` call:
+For example, a typical web framework might return a ``Response`` object from a ``render_to_response`` call:
.. code-block:: python
:linenos:
@@ -342,7 +260,7 @@ For example, instead of returning a ``Response`` object from a
return render_to_response('myapp:templates/mytemplate.pt', {'a':1},
request=request)
-You can return a Python dictionary:
+While you *can* do this in :app:`Pyramid`, you can also return a Python dictionary:
.. code-block:: python
:linenos:
@@ -353,547 +271,92 @@ You can return a Python dictionary:
def myview(request):
return {'a':1}
-When this view callable is called by Pyramid, the ``{'a':1}`` dictionary will
-be rendered to a response on your behalf. The string passed as ``renderer=``
-above is an :term:`asset specification`. It is in the form
-``packagename:directoryname/filename.ext``. In this case, it refers to the
-``mytemplate.pt`` file in the ``templates`` directory within the ``myapp``
-Python package. Asset specifications are omnipresent in Pyramid. See
-:ref:`intro_asset_specs` for more information.
-
-Example: :ref:`renderers_chapter`.
-
-Event system
-~~~~~~~~~~~~
-
-Pyramid emits *events* during its request processing lifecycle. You can
-subscribe any number of listeners to these events. For example, to be notified
-of a new request, you can subscribe to the ``NewRequest`` event. To be
-notified that a template is about to be rendered, you can subscribe to the
-``BeforeRender`` event, and so forth. Using an event publishing system as a
-framework notification feature instead of hardcoded hook points tends to make
-systems based on that framework less brittle.
-
-You can also use Pyramid's event system to send your *own* events. For
-example, if you'd like to create a system that is itself a framework, and may
-want to notify subscribers that a document has just been indexed, you can
-create your own event type (``DocumentIndexed`` perhaps) and send the event via
-Pyramid. Users of this framework can then subscribe to your event like they'd
-subscribe to the events that are normally sent by Pyramid itself.
-
-Example: :ref:`events_chapter` and :ref:`event_types`.
-
-Built-in internationalization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+By configuring your view to use a renderer, you tell :app:`Pyramid` to use the ``{'a':1}`` dictionary and the specified template to render a response on your behalf.
-Pyramid ships with internationalization-related features in its core:
-localization, pluralization, and creating message catalogs from source files
-and templates. Pyramid allows for a plurality of message catalogs via the use
-of translation domains. You can create a system that has its own translations
-without conflict with other translations in other domains.
+The string passed as ``renderer=`` above is an :term:`asset specification`. Asset specifications are widely used in :app:`Pyramid`. They allow for more reliable customization. See :ref:`intro_asset_specs` for more information.
-Example: :ref:`i18n_chapter`.
-
-HTTP caching
-~~~~~~~~~~~~
-
-Pyramid provides an easy way to associate views with HTTP caching policies. You
-can just tell Pyramid to configure your view with an ``http_cache`` statement,
-and it will take care of the rest::
-
- @view_config(http_cache=3600) # 60 minutes
- def myview(request): ....
-
-Pyramid will add appropriate ``Cache-Control`` and ``Expires`` headers to
-responses generated when this view is invoked.
-
-See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache``
-documentation for more information.
-
-Sessions
-~~~~~~~~
-
-Pyramid has built-in HTTP sessioning. This allows you to associate data with
-otherwise anonymous users between requests. Lots of systems do this. But
-Pyramid also allows you to plug in your own sessioning system by creating some
-code that adheres to a documented interface. Currently there is a binding
-package for the third-party Redis sessioning system that does exactly this. But
-if you have a specialized need (perhaps you want to store your session data in
-MongoDB), you can. You can even switch between implementations without
-changing your application code.
-
-Example: :ref:`sessions_chapter`.
-
-Speed
-~~~~~
-
-The Pyramid core is, as far as we can tell, at least marginally faster than any
-other existing Python web framework. It has been engineered from the ground up
-for speed. It only does as much work as absolutely necessary when you ask it
-to get a job done. Extraneous function calls and suboptimal algorithms in its
-core codepaths are avoided. It is feasible to get, for example, between 3500
-and 4000 requests per second from a simple Pyramid view on commodity dual-core
-laptop hardware and an appropriate WSGI server (:term:`mod_wsgi` or gunicorn). In any
-case, performance statistics are largely useless without requirements and
-goals, but if you need speed, Pyramid will almost certainly never be your
-application's bottleneck; at least no more than Python will be a bottleneck.
-
-Example: http://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html
-
-Exception views
-~~~~~~~~~~~~~~~
-
-Exceptions happen. Rather than deal with exceptions that might present
-themselves to a user in production in an ad-hoc way, Pyramid allows you to
-register an :term:`exception view`. Exception views are like regular Pyramid
-views, but they're only invoked when an exception "bubbles up" to Pyramid
-itself. For example, you might register an exception view for the
-:exc:`Exception` exception, which will catch *all* exceptions, and present a
-pretty "well, this is embarrassing" page. Or you might choose to register an
-exception view for only specific kinds of application-specific exceptions, such
-as an exception that happens when a file is not found, or an exception that
-happens when an action cannot be performed because the user doesn't have
-permission to do something. In the former case, you can show a pretty "Not
-Found" page; in the latter case you might show a login form.
-
-Example: :ref:`exception_views`.
-
-No singletons
-~~~~~~~~~~~~~
-
-Pyramid is written in such a way that it requires your application to have
-exactly zero "singleton" data structures. Or put another way, Pyramid doesn't
-require you to construct any "mutable globals". Or put even another different
-way, an import of a Pyramid application needn't have any "import-time side
-effects". This is esoteric-sounding, but if you've ever tried to cope with
-parameterizing a Django ``settings.py`` file for multiple installations of the
-same application, or if you've ever needed to monkey-patch some framework
-fixture so that it behaves properly for your use case, or if you've ever wanted
-to deploy your system using an asynchronous server, you'll end up appreciating
-this feature. It just won't be a problem. You can even run multiple copies of
-a similar but not identically configured Pyramid application within the same
-Python process. This is good for shared hosting environments, where RAM is at
-a premium.
-
-View predicates and many views per route
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Unlike many other systems, Pyramid allows you to associate more than one view
-per route. For example, you can create a route with the pattern ``/items`` and
-when the route is matched, you can shuffle off the request to one view if the
-request method is GET, another view if the request method is POST, etc. A
-system known as "view predicates" allows for this. Request method matching is
-the most basic thing you can do with a view predicate. You can also associate
-views with other request parameters, such as the elements in the query string,
-the Accept header, whether the request is an XHR request or not, and lots of
-other things. This feature allows you to keep your individual views clean.
-They won't need much conditional logic, so they'll be easier to test.
-
-Example: :ref:`view_configuration_parameters`.
-
-Transaction management
-~~~~~~~~~~~~~~~~~~~~~~
+Example: :ref:`renderers_chapter`.
-A couple of Pyramid's :term:`cookiecutter`\ s include a *transaction
-management* system, stolen from Zope. When you use this transaction management
-system, you cease being responsible for committing your data anymore. Instead
-Pyramid takes care of committing: it commits at the end of a request or aborts
-if there's an exception. Why is that a good thing? Having a centralized place
-for transaction management is a great thing. If, instead of managing your
-transactions in a centralized place, you sprinkle ``session.commit`` calls in
-your application logic itself, you can wind up in a bad place. Wherever you
-manually commit data to your database, it's likely that some of your other code
-is going to run *after* your commit. If that code goes on to do other important
-things after that commit, and an error happens in the later code, you can
-easily wind up with inconsistent data if you're not extremely careful. Some
-data will have been written to the database that probably should not have.
-Having a centralized commit point saves you from needing to think about this;
-it's great for lazy people who also care about data integrity. Either the
-request completes successfully, and all changes are committed, or it does not,
-and all changes are aborted.
-
-Pyramid's transaction management system allows you to synchronize commits
-between multiple databases. It also allows you to do things like conditionally
-send email if a transaction commits, but otherwise keep quiet.
-
-Example: :ref:`bfg_sql_wiki_tutorial` (note the lack of commit statements
-anywhere in application code).
-
-Configuration conflict detection
+Use events to coordinate actions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When a system is small, it's reasonably easy to keep it all in your head. But
-when systems grow large, you may have hundreds or thousands of configuration
-statements which add a view, add a route, and so forth.
-
-Pyramid's configuration system keeps track of your configuration statements. If
-you accidentally add two that are identical, or Pyramid can't make sense out of
-what it would mean to have both statements active at the same time, it will
-complain loudly at startup time. It's not dumb though. It will automatically
-resolve conflicting configuration statements on its own if you use the
-configuration :meth:`~pyramid.config.Configurator.include` system. "More local"
-statements are preferred over "less local" ones. This allows you to
-intelligently factor large systems into smaller ones.
-
-Example: :ref:`conflict_detection`.
-
-Configuration extensibility
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Unlike other systems, Pyramid provides a structured "include" mechanism (see
-:meth:`~pyramid.config.Configurator.include`) that allows you to combine
-applications from multiple Python packages. All the configuration statements
-that can be performed in your "main" Pyramid application can also be performed
-by included packages, including the addition of views, routes, subscribers, and
-even authentication and authorization policies. You can even extend or override
-an existing application by including another application's configuration in
-your own, overriding or adding new views and routes to it. This has the
-potential to allow you to create a big application out of many other smaller
-ones. For example, if you want to reuse an existing application that already
-has a bunch of routes, you can just use the ``include`` statement with a
-``route_prefix``. The new application will live within your application at an
-URL prefix. It's not a big deal, and requires little up-front engineering
-effort.
-
-For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.config import Configurator
-
- if __name__ == '__main__':
- config = Configurator()
- config.include('pyramid_jinja2')
- config.include('pyramid_exclog')
- config.include('some.other.guys.package', route_prefix='/someotherguy')
-
-.. seealso::
-
- See also :ref:`including_configuration` and
- :ref:`building_an_extensible_app`.
-
-Flexible authentication and authorization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Pyramid includes a flexible, pluggable authentication and authorization system.
-No matter where your user data is stored, or what scheme you'd like to use to
-permit your users to access your data, you can use a predefined Pyramid
-plugpoint to plug in your custom authentication and authorization code. If you
-want to change these schemes later, you can just change it in one place rather
-than everywhere in your code. It also ships with prebuilt well-tested
-authentication and authorization schemes out of the box. But what if you don't
-want to use Pyramid's built-in system? You don't have to. You can just write
-your own bespoke security code as you would in any other system.
-
-Example: :ref:`enabling_authorization_policy`.
-
-Traversal
-~~~~~~~~~
-
-:term:`Traversal` is a concept stolen from :term:`Zope`. It allows you to
-create a tree of resources, each of which can be addressed by one or more URLs.
-Each of those resources can have one or more *views* associated with it. If
-your data isn't naturally treelike, or you're unwilling to create a treelike
-representation of your data, you aren't going to find traversal very useful.
-However, traversal is absolutely fantastic for sites that need to be
-arbitrarily extensible. It's a lot easier to add a node to a tree than it is to
-shoehorn a route into an ordered list of other routes, or to create another
-entire instance of an application to service a department and glue code to
-allow disparate apps to share data. It's a great fit for sites that naturally
-lend themselves to changing departmental hierarchies, such as content
-management systems and document management systems. Traversal also lends
-itself well to systems that require very granular security ("Bob can edit
-*this* document" as opposed to "Bob can edit documents").
-
-Examples: :ref:`hello_traversal_chapter` and
-:ref:`much_ado_about_traversal_chapter`.
-
-Tweens
-~~~~~~
-
-Pyramid has a sort of internal WSGI-middleware-ish pipeline that can be hooked
-by arbitrary add-ons named "tweens". The debug toolbar is a "tween", and the
-``pyramid_tm`` transaction manager is also. Tweens are more useful than WSGI
-:term:`middleware` in some circumstances because they run in the context of
-Pyramid itself, meaning you have access to templates and other renderers, a
-"real" request object, and other niceties.
-
-Example: :ref:`registering_tweens`.
-
-View response adapters
-~~~~~~~~~~~~~~~~~~~~~~
-
-A lot is made of the aesthetics of what *kinds* of objects you're allowed to
-return from view callables in various frameworks. In a previous section in
-this document, we showed you that, if you use a :term:`renderer`, you can
-usually return a dictionary from a view callable instead of a full-on
-:term:`Response` object. But some frameworks allow you to return strings or
-tuples from view callables. When frameworks allow for this, code looks
-slightly prettier, because fewer imports need to be done, and there is less
-code. For example, compare this:
-
-.. code-block:: python
- :linenos:
-
- def aview(request):
- return "Hello world!"
+When writing web applications, it is often important to have your code run at a specific point in the lifecycle of a request. In :app:`Pyramid`, you can accomplish this using *subscribers* and *events*.
-To this:
+For example, you might have a job that needs to be done each time your application handles a new request. :app:`Pyramid` emits a ``NewRequest`` event at this point in the request handling lifecycle. You can register your code as a subscriber to this event using a clear, declarative style:
.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- def aview(request):
- return Response("Hello world!")
+ from pyramid.events import NewRequest
+ from pyramid.events import subscriber
-The former is "prettier", right?
+ @subscriber(NewRequest)
+ def my_job(event):
+ do_something(event.request)
-Out of the box, if you define the former view callable (the one that simply
-returns a string) in Pyramid, when it is executed, Pyramid will raise an
-exception. This is because "explicit is better than implicit", in most cases,
-and by default Pyramid wants you to return a :term:`Response` object from a
-view callable. This is because there's usually a heck of a lot more to a
-response object than just its body. But if you're the kind of person who
-values such aesthetics, we have an easy way to allow for this sort of thing:
+:app:`Pyramid`\ 's event system can be extended as well. If you need, you can create events of your own and send them using :app:`Pyramid`\ 's event system. Then anyone working with your application can subscribe to your events and coordinate their code with yours.
-.. code-block:: python
- :linenos:
-
- from pyramid.config import Configurator
- from pyramid.response import Response
-
- def string_response_adapter(s):
- response = Response(s)
- response.content_type = 'text/html'
- return response
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_response_adapter(string_response_adapter, basestring)
-
-Do that once in your Pyramid application at startup. Now you can return
-strings from any of your view callables, e.g.:
-
-.. code-block:: python
- :linenos:
-
- def helloview(request):
- return "Hello world!"
-
- def goodbyeview(request):
- return "Goodbye world!"
-
-Oh noes! What if you want to indicate a custom content type? And a custom
-status code? No fear:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.config import Configurator
-
- def tuple_response_adapter(val):
- status_int, content_type, body = val
- response = Response(body)
- response.content_type = content_type
- response.status_int = status_int
- return response
-
- def string_response_adapter(body):
- response = Response(body)
- response.content_type = 'text/html'
- response.status_int = 200
- return response
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_response_adapter(string_response_adapter, basestring)
- config.add_response_adapter(tuple_response_adapter, tuple)
-
-Once this is done, both of these view callables will work:
-
-.. code-block:: python
- :linenos:
-
- def aview(request):
- return "Hello world!"
-
- def anotherview(request):
- return (403, 'text/plain', "Forbidden")
-
-Pyramid defaults to explicit behavior, because it's the most generally useful,
-but provides hooks that allow you to adapt the framework to localized aesthetic
-desires.
-
-.. seealso::
-
- See also :ref:`using_iresponse`.
-
-"Global" response object
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-"Constructing these response objects in my view callables is such a chore! And
-I'm way too lazy to register a response adapter, as per the prior section," you
-say. Fine. Be that way:
-
-.. code-block:: python
- :linenos:
-
- def aview(request):
- response = request.response
- response.body = 'Hello world!'
- response.content_type = 'text/plain'
- return response
-
-.. seealso::
-
- See also :ref:`request_response_attr`.
-
-Automating repetitive configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Example: :ref:`events_chapter` and :ref:`event_types`.
-Does Pyramid's configurator allow you to do something, but you're a little
-adventurous and just want it a little less verbose? Or you'd like to offer up
-some handy configuration feature to other Pyramid users without requiring that
-we change Pyramid? You can extend Pyramid's :term:`Configurator` with your own
-directives. For example, let's say you find yourself calling
-:meth:`pyramid.config.Configurator.add_view` repetitively. Usually you can
-take the boring away by using existing shortcuts, but let's say that this is a
-case where there is no such shortcut:
+Build international applications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. code-block:: python
- :linenos:
+:app:`Pyramid` ships with internationalization-related features in its core: localization, pluralization, and creating message catalogs from source files and templates. :app:`Pyramid` allows for a plurality of message catalogs via the use of translation domains. You can create a system that has its own translations without conflict with other translations in other domains.
- from pyramid.config import Configurator
+Example: :ref:`i18n_chapter`.
- config = Configurator()
- config.add_route('xhr_route', '/xhr/{id}')
- config.add_view('my.package.GET_view', route_name='xhr_route',
- xhr=True, permission='view', request_method='GET')
- config.add_view('my.package.POST_view', route_name='xhr_route',
- xhr=True, permission='view', request_method='POST')
- config.add_view('my.package.HEAD_view', route_name='xhr_route',
- xhr=True, permission='view', request_method='HEAD')
+Build efficient applications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Pretty tedious right? You can add a directive to the Pyramid configurator to
-automate some of the tedium away:
+:app:`Pyramid` provides an easy way to *cache* the results of slow or expensive views. You can indicate in view configuration that you want a view to be cached:
.. code-block:: python
- :linenos:
- from pyramid.config import Configurator
+ @view_config(http_cache=3600) # 60 minutes
+ def myview(request):
+ # ...
- def add_protected_xhr_views(config, module):
- module = config.maybe_dotted(module)
- for method in ('GET', 'POST', 'HEAD'):
- view = getattr(module, 'xhr_%s_view' % method, None)
- if view is not None:
- config.add_view(view, route_name='xhr_route', xhr=True,
- permission='view', request_method=method)
+:app:`Pyramid` will automatically add the appropriate ``Cache-Control`` and ``Expires`` headers to the response it creates.
- config = Configurator()
- config.add_directive('add_protected_xhr_views', add_protected_xhr_views)
+See the :meth:`~pyramid.config.Configurator.add_view` method's ``http_cache`` documentation for more information.
-Once that's done, you can call the directive you've just added as a method of
-the Configurator object:
+Build fast applications
+~~~~~~~~~~~~~~~~~~~~~~~
-.. code-block:: python
- :linenos:
+The :app:`Pyramid` core is fast. It has been engineered from the ground up for speed. It only does as much work as absolutely necessary when you ask it to get a job done. If you need speed from your application, :app:`Pyramid` is the right choice for you.
- config.add_route('xhr_route', '/xhr/{id}')
- config.add_protected_xhr_views('my.package')
+Example: https://blog.curiasolutions.com/pages/the-great-web-framework-shootout.html
-Your previously repetitive configuration lines have now morphed into one line.
+Store session data
+~~~~~~~~~~~~~~~~~~
-You can share your configuration code with others this way, too, by packaging
-it up and calling :meth:`~pyramid.config.Configurator.add_directive` from
-within a function called when another user uses the
-:meth:`~pyramid.config.Configurator.include` method against your code.
+:app:`Pyramid` has built-in support for HTTP sessions, so you can associate data with specific users between requests. Lots of other frameworks also support sessions. But :app:`Pyramid` allows you to plug in your own custom sessioning system. So long as your system conforms to a documented interface, you can drop it in in place of the provided system.
-.. seealso::
+Currently there is a binding package for the third-party Redis sessioning system that does exactly this. But if you have a specialized need (perhaps you want to store your session data in MongoDB), you can. You can even switch between implementations without changing your application code.
- See also :ref:`add_directive`.
+Example: :ref:`sessions_chapter`.
-Programmatic introspection
+Handle problems with grace
~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you're building a large system that other users may plug code into, it's
-useful to be able to get an enumeration of what code they plugged in *at
-application runtime*. For example, you might want to show them a set of tabs
-at the top of the screen based on an enumeration of views they registered.
-
-This is possible using Pyramid's :term:`introspector`.
-
-Here's an example of using Pyramid's introspector from within a view callable:
+Mistakes happen. Problems crop up. No one writes bug-free code. :app:`Pyramid`provides a way to handle the exceptions your code encounters. An :term:`exception view` is a special kind of view which is automatically called when a particular exception type arises without being handled by your application.
-.. code-block:: python
- :linenos:
+For example, you might register an exception view for the :exc:`Exception` exception type, which will catch *all* exceptions, and present a pretty "well, this is embarrassing" page. Or you might choose to register an exception view for only certain application-specific exceptions. You can make one for when a file is not found, or when the user doesn't have permission to do something. In the former case, you can show a pretty "Not Found" page; in the latter case you might show a login form.
- from pyramid.view import view_config
- from pyramid.response import Response
+Example: :ref:`exception_views`.
- @view_config(route_name='bar')
- def show_current_route_pattern(request):
- introspector = request.registry.introspector
- route_name = request.matched_route.name
- route_intr = introspector.get('routes', route_name)
- return Response(str(route_intr['pattern']))
+And much, much more...
+~~~~~~~~~~~~~~~~~~~~~~
-.. seealso::
+:app:`Pyramid` has been built with a number of other sophisticated design features that make it adaptable. Read more about them below.
- See also :ref:`using_introspection`.
+.. toctree::
+ :maxdepth: 2
-Python 3 compatibility
-~~~~~~~~~~~~~~~~~~~~~~
+ advanced-features
-Pyramid and most of its add-ons are Python 3 compatible. If you develop a
-Pyramid application today, you won't need to worry that five years from now
-you'll be backwatered because there are language features you'd like to use but
-your framework doesn't support newer Python versions.
-
-Testing
-~~~~~~~
-
-Every release of Pyramid has 100% statement coverage via unit and integration
-tests, as measured by the ``coverage`` tool available on PyPI. It also has
-greater than 95% decision/condition coverage as measured by the
-``instrumental`` tool available on PyPI. It is automatically tested by Travis,
-and Jenkins on Python 2.7, Python 3.4, Python 3.5, Python 3.6, and PyPy
-after each commit to its GitHub repository. Official Pyramid add-ons are held
-to a similar testing standard. We still find bugs in Pyramid and its official
-add-ons, but we've noticed we find a lot more of them while working on other
-projects that don't have a good testing regime.
-
-Travis: https://travis-ci.org/Pylons/pyramid
-Jenkins: http://jenkins.pylonsproject.org/job/pyramid/
-
-Support
-~~~~~~~
-
-It's our goal that no Pyramid question go unanswered. Whether you ask a
-question on IRC, on the Pylons-discuss mailing list, or on StackOverflow,
-you're likely to get a reasonably prompt response. We don't tolerate "support
-trolls" or other people who seem to get their rocks off by berating fellow
-users in our various official support channels. We try to keep it well-lit and
-new-user-friendly.
-
-Example: Visit irc\://freenode.net#pyramid (the ``#pyramid`` channel on
-irc.freenode.net in an IRC client) or the pylons-discuss maillist at
-https://groups.google.com/forum/#!forum/pylons-discuss.
-Documentation
-~~~~~~~~~~~~~
-It's a constant struggle, but we try to maintain a balance between completeness
-and new-user-friendliness in the official narrative Pyramid documentation
-(concrete suggestions for improvement are always appreciated, by the way). We
-also maintain a "cookbook" of recipes, which are usually demonstrations of
-common integration scenarios too specific to add to the official narrative
-docs. In any case, the Pyramid documentation is comprehensive.
-Example: The :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>`.
.. index::
single: Pylons Project
@@ -901,10 +364,7 @@ Example: The :ref:`Pyramid Community Cookbook <cookbook:pyramid-cookbook>`.
What Is The Pylons Project?
---------------------------
-:app:`Pyramid` is a member of the collection of software published under the
-Pylons Project. Pylons software is written by a loose-knit community of
-contributors. The `Pylons Project website <http://www.pylonsproject.org>`_
-includes details about how :app:`Pyramid` relates to the Pylons Project.
+:app:`Pyramid` is a member of the collection of software published under the Pylons Project. Pylons software is written by a loose-knit community of contributors. The `Pylons Project website <https://pylonsproject.org>`_ includes details about how :app:`Pyramid` relates to the Pylons Project.
.. index::
single: pyramid and other frameworks
@@ -914,72 +374,16 @@ includes details about how :app:`Pyramid` relates to the Pylons Project.
single: MVC
:app:`Pyramid` and Other Web Frameworks
-------------------------------------------
-
-The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made
-in July of 2008. At the end of 2010, we changed the name of :mod:`repoze.bfg`
-to :app:`Pyramid`. It was merged into the Pylons project as :app:`Pyramid` in
-November of that year.
-
-:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version 1.0), and
-:term:`Django`. As a result, :app:`Pyramid` borrows several concepts and
-features from each, combining them into a unique web framework.
-
-Many features of :app:`Pyramid` trace their origins back to :term:`Zope`. Like
-Zope applications, :app:`Pyramid` applications can be easily extended. If you
-obey certain constraints, the application you produce can be reused, modified,
-re-integrated, or extended by third-party developers without forking the
-original application. The concepts of :term:`traversal` and declarative
-security in :app:`Pyramid` were pioneered first in Zope.
-
-The :app:`Pyramid` concept of :term:`URL dispatch` is inspired by the
-:term:`Routes` system used by :term:`Pylons` version 1.0. Like Pylons version
-1.0, :app:`Pyramid` is mostly policy-free. It makes no assertions about which
-database you should use. Pyramid no longer has built-in templating facilities
-as of version 1.5a2, but instead officially supports bindings for templating
-languages, including Chameleon, Jinja2, and Mako. In essence, it only supplies
-a mechanism to map URLs to :term:`view` code, along with a set of conventions
-for calling those views. You are free to use third-party components that fit
-your needs in your applications.
-
-The concept of :term:`view` is used by :app:`Pyramid` mostly as it would be by
-Django. :app:`Pyramid` has a documentation culture more like Django's than
-like Zope's.
-
-Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a :app:`Pyramid`
-application developer may use completely imperative code to perform common
-framework configuration tasks such as adding a view or a route. In Zope,
-:term:`ZCML` is typically required for similar purposes. In :term:`Grok`, a
-Zope-based web framework, :term:`decorator` objects and class-level
-declarations are used for this purpose. Out of the box, Pyramid supports
-imperative and decorator-based configuration. :term:`ZCML` may be used via an
-add-on package named ``pyramid_zcml``.
-
-Also unlike :term:`Zope` and other "full-stack" frameworks such as
-:term:`Django`, :app:`Pyramid` makes no assumptions about which persistence
-mechanisms you should use to build an application. Zope applications are
-typically reliant on :term:`ZODB`. :app:`Pyramid` allows you to build
-:term:`ZODB` applications, but it has no reliance on the ZODB software.
-Likewise, :term:`Django` tends to assume that you want to store your
-application's data in a relational database. :app:`Pyramid` makes no such
-assumption, allowing you to use a relational database, and neither encouraging
-nor discouraging the decision.
-
-Other Python web frameworks advertise themselves as members of a class of web
-frameworks named `model-view-controller
-<https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_
-frameworks. Insofar as this term has been claimed to represent a class of web
-frameworks, :app:`Pyramid` also generally fits into this class.
-
-.. sidebar:: You Say :app:`Pyramid` is MVC, but Where's the Controller?
-
- The :app:`Pyramid` authors believe that the MVC pattern just doesn't really
- fit the web very well. In a :app:`Pyramid` application, there is a resource
- tree which represents the site structure, and views which tend to present
- the data stored in the resource tree and a user-defined "domain model".
- However, no facility provided *by the framework* actually necessarily maps
- to the concept of a "controller" or "model". So if you had to give it some
- acronym, I guess you'd say :app:`Pyramid` is actually an "RV" framework
- rather than an "MVC" framework. "MVC", however, is close enough as a
- general classification moniker for purposes of comparison with other web
- frameworks.
+---------------------------------------
+
+The first release of :app:`Pyramid`\ 's predecessor (named :mod:`repoze.bfg`) was made in July of 2008. At the end of 2010, we changed the name of :mod:`repoze.bfg` to :app:`Pyramid`. It was merged into the Pylons project as :app:`Pyramid` in November of that year.
+
+:app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version 1.0), and :term:`Django`. As a result, :app:`Pyramid` borrows several concepts and features from each, combining them into a unique web framework.
+
+Similar to :term:`Zope`, :app:`Pyramid` applications may easily be extended. If you work within the constraints of the framework, you can produce applications that can be reused, modified, or extended without needing to modify the original application code. :app:`Pyramid` also inherits the concepts of :term:`traversal` and declarative security from Zope.
+
+Similar to :term:`Pylons` version 1.0, :app:`Pyramid` is largely free of policy. It makes no assertions about which database or template system you should use. You are free to use whatever third-party components fit the needs of your specific application. :app:`Pyramid` also inherits its approach to :term:`URL dispatch` from Pylons.
+
+Similar to :term:`Django`, :app:`Pyramid` values extensive documentation. In addition, the concept of a :term:`view` is used by :app:`Pyramid` much as it would be by Django.
+
+Other Python web frameworks advertise themselves as members of a class of web frameworks named `model-view-controller <https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`_ frameworks. The authors of :app:`Pyramid` do not believe that the MVC pattern fits the web particularly well. However, if this abstraction works for you, :app:`Pyramid` also generally fits into this class.
diff --git a/docs/narr/logging.rst b/docs/narr/logging.rst
index 87682158b..a7ee0f1f8 100644
--- a/docs/narr/logging.rst
+++ b/docs/narr/logging.rst
@@ -16,7 +16,7 @@ to send log messages to loggers that you've configured.
cookiecutter which does not create these files, the configuration information in
this chapter may not be applicable.
-.. index:
+.. index::
pair: settings; logging
pair: .ini; logging
pair: logging; configuration
@@ -67,12 +67,12 @@ In this logging configuration:
2007-08-17 15:04:08,704 INFO [packagename] Loading resource, id: 86
-- a logger named ``myapp`` is configured that logs messages sent at a level
+- a logger named ``myproject`` is configured that logs messages sent at a level
above or equal to ``DEBUG`` to stderr in the same format as the root logger.
The ``root`` logger will be used by all applications in the Pyramid process
that ask for a logger (via ``logging.getLogger``) that has a name which begins
-with anything except your project's package name (e.g., ``myapp``). The logger
+with anything except your project's package name (e.g., ``myproject``). The logger
with the same name as your package name is reserved for your own usage in your
:app:`Pyramid` application. Its existence means that you can log to a known
logging location from any :app:`Pyramid` application generated via a cookiecutter.
@@ -96,10 +96,10 @@ Sending Logging Messages
------------------------
Python's special ``__name__`` variable refers to the current module's fully
-qualified name. From any module in a package named ``myapp``, the ``__name__``
-builtin variable will always be something like ``myapp``, or
-``myapp.subpackage`` or ``myapp.package.subpackage`` if your project is named
-``myapp``. Sending a message to this logger will send it to the ``myapp``
+qualified name. From any module in a package named ``myproject``, the ``__name__``
+builtin variable will always be something like ``myproject``, or
+``myproject.subpackage`` or ``myproject.package.subpackage`` if your project is named
+``myproject``. Sending a message to this logger will send it to the ``myproject``
logger.
To log messages to the package-specific logger configured in your ``.ini``
@@ -123,7 +123,7 @@ This will result in the following printed to the console, on ``stderr``:
.. code-block:: text
- 16:20:20,440 DEBUG [myapp.views] Returning: Hello World!
+ 16:20:20,440 DEBUG [myproject.views] Returning: Hello World!
(content-type: text/plain)
Filtering log messages
@@ -150,7 +150,7 @@ then add it to the list of loggers:
.. code-block:: ini
[loggers]
- keys = root, myapp, sqlalchemy.pool
+ keys = root, myproject, sqlalchemy.pool
No handlers need to be configured for this logger as by default non-root
loggers will propagate their log records up to their parent logger's handlers.
@@ -165,16 +165,16 @@ level is set to ``INFO``, whereas the application's log level is set to
# Begin logging configuration
[loggers]
- keys = root, myapp
+ keys = root, myproject
- [logger_myapp]
+ [logger_myproject]
level = DEBUG
handlers =
- qualname = myapp
+ qualname = myproject
-All of the child loggers of the ``myapp`` logger will inherit the ``DEBUG``
-level unless they're explicitly set differently. Meaning the ``myapp.views``,
-``myapp.models``, and all your app's modules' loggers by default have an
+All of the child loggers of the ``myproject`` logger will inherit the ``DEBUG``
+level unless they're explicitly set differently. Meaning the ``myproject.views``,
+``myproject.models``, and all your app's modules' loggers by default have an
effective level of ``DEBUG`` too.
For more advanced filtering, the logging module provides a
@@ -191,7 +191,7 @@ To capture log output to a separate file, use :class:`logging.FileHandler` (or
[handler_filelog]
class = FileHandler
- args = ('%(here)s/myapp.log','a')
+ args = ('%(here)s/myproject.log','a')
level = INFO
formatter = generic
@@ -200,7 +200,7 @@ Before it's recognized, it needs to be added to the list of handlers:
.. code-block:: ini
[handlers]
- keys = console, myapp, filelog
+ keys = console, myproject, filelog
and finally utilized by a logger.
@@ -211,7 +211,7 @@ and finally utilized by a logger.
handlers = console, filelog
These final three lines of configuration direct all of the root logger's output
-to the ``myapp.log`` as well as the console.
+to the ``myproject.log`` as well as the console.
Logging Exceptions
------------------
@@ -219,7 +219,7 @@ Logging Exceptions
To log or email exceptions generated by your :app:`Pyramid` application, use
the :term:`pyramid_exclog` package. Details about its configuration are in its
`documentation
-<http://docs.pylonsproject.org/projects/pyramid_exclog/en/latest/>`_.
+<https://docs.pylonsproject.org/projects/pyramid_exclog/en/latest/>`_.
.. index::
single: TransLogger
@@ -294,7 +294,7 @@ output to the console when we request a page:
.. code-block:: text
- 00:50:53,694 INFO [myapp.views] Returning: Hello World!
+ 00:50:53,694 INFO [myproject.views] Returning: Hello World!
(content-type: text/plain)
00:50:53,695 INFO [wsgi] 192.168.1.111 - - [11/Aug/2011:20:09:33 -0700] "GET /hello
HTTP/1.1" 404 - "-"
@@ -310,7 +310,7 @@ that the ``wsgi`` logger is configured and uses this handler accordingly:
# Begin logging configuration
[loggers]
- keys = root, myapp, wsgi
+ keys = root, myproject, wsgi
[handlers]
keys = console, accesslog
diff --git a/docs/narr/myproject/README.txt b/docs/narr/myproject/README.txt
index 41ef0ff91..2ffc0acba 100644
--- a/docs/narr/myproject/README.txt
+++ b/docs/narr/myproject/README.txt
@@ -1,5 +1,5 @@
MyProject
-===============================
+=========
Getting Started
---------------
diff --git a/docs/narr/myproject/development.ini b/docs/narr/myproject/development.ini
index 5d110805a..7e5496881 100644
--- a/docs/narr/myproject/development.ini
+++ b/docs/narr/myproject/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
+# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -24,11 +24,11 @@ pyramid.includes =
[server:main]
use = egg:waitress#main
-listen = 127.0.0.1:6543 [::1]:6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
+# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/narr/myproject/myproject/templates/layout.jinja2 b/docs/narr/myproject/myproject/templates/layout.jinja2
index bfac9e64e..1baca52bd 100644
--- a/docs/narr/myproject/myproject/templates/layout.jinja2
+++ b/docs/narr/myproject/myproject/templates/layout.jinja2
@@ -11,15 +11,15 @@
<title>Cookiecutter Starter project 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">
+ <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- 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 -->
<!--[if lt IE 9]>
- <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
- <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
+ <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
+ <script src="//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js" integrity="sha384-ZoaMbDF+4LeFxg6WdScQ9nnR1QC2MIRxA1O9KWEXQwns1G8UNyIEZIQidzb0T1fo" crossorigin="anonymous"></script>
<![endif]-->
</head>
@@ -42,7 +42,7 @@
<ul>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
<li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
- <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
+ <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="https://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
</div>
@@ -58,7 +58,7 @@
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
- <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
- <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
+ <script src="//code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
+ <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</body>
</html>
diff --git a/docs/narr/myproject/myproject/templates/mytemplate.jinja2 b/docs/narr/myproject/myproject/templates/mytemplate.jinja2
index ce042215d..f2e7283f8 100644
--- a/docs/narr/myproject/myproject/templates/mytemplate.jinja2
+++ b/docs/narr/myproject/myproject/templates/mytemplate.jinja2
@@ -3,6 +3,6 @@
{% block content %}
<div class="content">
<h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
- <p class="lead">Welcome to <span class="font-normal">MyProject</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
+ <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
{% endblock content %}
diff --git a/docs/narr/myproject/production.ini b/docs/narr/myproject/production.ini
index 13be488e7..7060ef854 100644
--- a/docs/narr/myproject/production.ini
+++ b/docs/narr/myproject/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
+# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -22,7 +22,7 @@ listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
+# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/narr/myproject/setup.py b/docs/narr/myproject/setup.py
index 00e377349..153a659ba 100644
--- a/docs/narr/myproject/setup.py
+++ b/docs/narr/myproject/setup.py
@@ -9,6 +9,7 @@ with open(os.path.join(here, 'CHANGES.txt')) as f:
CHANGES = f.read()
requires = [
+ 'plaster_pastedeploy',
'pyramid',
'pyramid_jinja2',
'pyramid_debugtoolbar',
diff --git a/docs/narr/paste.rst b/docs/narr/paste.rst
index 2d4e76e24..c02036f69 100644
--- a/docs/narr/paste.rst
+++ b/docs/narr/paste.rst
@@ -21,17 +21,12 @@ debugging an application.
This chapter is not a replacement for documentation about PasteDeploy; it only
contextualizes the use of PasteDeploy within Pyramid. For detailed
-documentation, see http://pythonpaste.org/deploy/.
+documentation, see https://pastedeploy.readthedocs.io/en/latest/.
PasteDeploy
-----------
-:term:`PasteDeploy` is the system that Pyramid uses to allow :term:`deployment
-settings` to be specified using an ``.ini`` configuration file format. It also
-allows the ``pserve`` command to work. Its configuration format provides a
-convenient place to define application :term:`deployment settings` and WSGI
-server settings, and its server runner allows you to stop and start a Pyramid
-application easily.
+:term:`plaster` is the system that Pyramid uses to load settings from configuration files. The most common format for these files is an ``.ini`` format structured in a way defined by :term:`PasteDeploy`. The format supports mechanisms to define WSGI app :term:`deployment settings`, WSGI server settings and logging. This allows the ``pserve`` command to work, allowing you to stop and start a Pyramid application easily.
.. _pastedeploy_entry_points:
@@ -96,3 +91,8 @@ applications, servers, and :term:`middleware` defined within the configuration
file. The values in a ``[DEFAULT]`` section will be passed to your
application's ``main`` function as ``global_config`` (see the reference to the
``main`` function in :ref:`init_py`).
+
+Alternative Configuration File Formats
+--------------------------------------
+
+It is possible to use different file formats with :app:`Pyramid` if you do not like :term:`PasteDeploy`. Under the hood all command-line scripts such as ``pserve`` and ``pshell`` pass the ``config_uri`` (e.g. ``development.ini`` or ``production.ini``) to the :term:`plaster` library which performs a lookup for an appropriate parser. For ``.ini`` files it uses PasteDeploy but you can register your own configuration formats that plaster will find instead.
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index f32fad370..c54e28137 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -43,7 +43,7 @@ Pyramid cookiecutters released under the Pylons Project differ from each other o
- the mechanism they use to map URLs to code (:term:`URL dispatch` or :term:`traversal`)
-- templating libraries (:term:`Jinja2` or :term:`Chameleon`)
+- templating libraries (:term:`Jinja2`, :term:`Chameleon`, or :term:`Mako`)
* `pyramid-cookiecutter-starter <https://github.com/Pylons/pyramid-cookiecutter-starter>`_
* `pyramid-cookiecutter-alchemy <https://github.com/Pylons/pyramid-cookiecutter-alchemy>`_
@@ -52,7 +52,7 @@ Pyramid cookiecutters released under the Pylons Project differ from each other o
These cookiecutters include:
``pyramid-cookiecutter-starter``
- :term:`URL dispatch` for routing and :term:`Jinja2` for templating
+ :term:`URL dispatch` for routing and either :term:`Jinja2`, :term:`Chameleon`, or :term:`Mako` for templating
``pyramid-cookiecutter-alchemy``
SQLite for persistent storage, :term:`SQLAlchemy` for an ORM, :term:`URL dispatch` for routing, and :term:`Jinja2` for templating.
@@ -85,14 +85,21 @@ On all platforms, generate a project using cookiecutter.
.. code-block:: bash
- $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter
+ $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
If prompted for the first item, accept the default ``yes`` by hitting return.
-#. ``You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before. Is it
- okay to delete and re-clone it? [yes]:``
-#. ``project_name [Pyramid Scaffold]: myproject``
-#. ``repo_name [scaffold]: myproject``
+.. code-block:: text
+
+ You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.
+ Is it okay to delete and re-clone it? [yes]: yes
+ project_name [Pyramid Scaffold]: myproject
+ repo_name [myproject]: myproject
+ Select template_language:
+ 1 - jinja2
+ 2 - chameleon
+ 3 - mako
+ Choose from 1, 2, 3 [1]: 1
We then run through the following commands.
@@ -325,7 +332,7 @@ 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 ``listen`` value in the
-``[server:main]`` section, changing it from ``127.0.0.1:6543 [::1]:6543`` to ``*:6543``
+``[server:main]`` section, changing it from ``localhost:6543`` to ``*:6543``
(this is equivalent to ``0.0.0.0:6543 [::]:6543``). For example:
.. code-block:: ini
@@ -349,8 +356,8 @@ IPv6. ``[::]`` means the same as ``0.0.0.0`` but for IPv6 protocol.
You can change the port on which the server runs on by changing the same
portion of the ``development.ini`` file. For example, you can change the
-``listen = 127.0.0.1:6543 [::1]:6543`` line in the ``development.ini`` file's ``[server:main]``
-section to ``listen = 127:0.0.1:8080 [::1]:8080`` to run the server on port 8080 instead of port 6543.
+``listen = localhost:6543`` line in the ``development.ini`` file's ``[server:main]``
+section to ``listen = localhost:8080`` to run the server on port 8080 instead of port 6543.
You can shut down a server started this way by pressing ``Ctrl-C`` (or
``Ctrl-Break`` on Windows).
@@ -733,7 +740,7 @@ testing, as well as 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 `Python Packaging User Guide
- <https://packaging.python.org/en/latest/>`_ and `Setuptools documentation
+ <https://packaging.python.org/>`_ and `Setuptools documentation
<http://pythonhosted.org/setuptools/>`_.
Our generated ``setup.py`` looks like this:
@@ -1105,7 +1112,7 @@ Automatically Reloading Your Code
During development, it can be really useful to automatically have the
webserver restart when you make changes. ``pserve`` has a ``--reload`` switch
to enable this. It uses the
-`hupper <http://docs.pylonsproject.org/projects/hupper/en/latest/>`_ package
+`hupper <https://docs.pylonsproject.org/projects/hupper/en/latest/>`_ package
to enable this behavior. When your code crashes, ``hupper`` will wait for
another change or the ``SIGHUP`` signal before restarting again.
@@ -1134,7 +1141,7 @@ serve it many times. When you change it, you want ``pserve`` to restart:
[pserve]
watch_files =
- myapp/static/favicon.ico
+ myproject/static/favicon.ico
Paths may be absolute or relative to the configuration file. They may also
be an :term:`asset specification`. These paths are passed to ``hupper``, which
diff --git a/docs/narr/scaffolding.rst b/docs/narr/scaffolding.rst
index 27239d34e..82ae0f9ac 100644
--- a/docs/narr/scaffolding.rst
+++ b/docs/narr/scaffolding.rst
@@ -27,7 +27,7 @@ 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 `Packaging and Distributing Projects
-<https://packaging.python.org/en/latest/distributing/>`_ for more information
+<https://packaging.python.org/tutorials/distributing-packages/>`_ 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``.
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 77e7fd707..0265152fa 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -146,7 +146,7 @@ For example, the following view declaration protects the view named
# config is an instance of pyramid.config.Configurator
config.add_view('mypackage.views.blog_entry_add_view',
- name='add_entry.html',
+ name='add_entry.html',
context='mypackage.resources.Blog',
permission='add')
@@ -725,7 +725,7 @@ object that implements the following interface:
""" Return ``True`` if any of the ``principals`` is allowed the
``permission`` in the current ``context``, else return ``False``
"""
-
+
def principals_allowed_by_permission(self, context, permission):
""" Return a set of principal identifiers allowed by the
``permission`` in ``context``. This behavior is optional; if you
@@ -765,3 +765,215 @@ 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.
+
+.. index::
+ single: preventing cross-site request forgery attacks
+ single: cross-site request forgery attacks, prevention
+
+Preventing Cross-Site Request Forgery Attacks
+---------------------------------------------
+
+`Cross-site request forgery
+<https://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
+phenomenon whereby a user who is logged in to your website might inadvertantly
+load a URL because it is linked from, or embedded in, an attacker's website.
+If the URL is one that may modify or delete data, the consequences can be dire.
+
+You can avoid most of these attacks by issuing a unique token to the browser
+and then requiring that it be present in all potentially unsafe requests.
+:app:`Pyramid` provides facilities to create and check CSRF tokens.
+
+By default :app:`Pyramid` comes with a session-based CSRF implementation
+:class:`pyramid.csrf.SessionCSRFStoragePolicy`. To use it, you must first enable
+a :term:`session factory` as described in
+:ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`. Alternatively, you can use
+a cookie-based implementation :class:`pyramid.csrf.CookieCSRFStoragePolicy` which gives
+some additional flexibility as it does not require a session for each user.
+You can also define your own implementation of
+:class:`pyramid.interfaces.ICSRFStoragePolicy` and register it with the
+:meth:`pyramid.config.Configurator.set_csrf_storage_policy` directive.
+
+For example:
+
+.. code-block:: python
+
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ config.set_csrf_storage_policy(MyCustomCSRFPolicy())
+
+.. index::
+ single: csrf.get_csrf_token
+
+Using the ``csrf.get_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To get the current CSRF token, use the
+:data:`pyramid.csrf.get_csrf_token` method.
+
+.. code-block:: python
+
+ from pyramid.csrf import get_csrf_token
+ token = get_csrf_token(request)
+
+The ``get_csrf_token()`` method accepts a single argument: the request. It
+returns a CSRF *token* string. If ``get_csrf_token()`` or ``new_csrf_token()``
+was invoked previously for this user, then the existing token will be returned.
+If no CSRF token previously existed for this user, then a new token will be set
+into the session and returned. The newly created token will be opaque and
+randomized.
+
+.. _get_csrf_token_in_templates:
+
+Using the ``get_csrf_token`` global in templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Templates have a ``get_csrf_token()`` method inserted into their globals, which
+allows you to get the current token without modifying the view code. This
+method takes no arguments and returns a CSRF token string. You can use the
+returned token as the value of a hidden field in a form that posts to a method
+that requires elevated privileges, or supply it as a request header in AJAX
+requests.
+
+For example, include the CSRF token as a hidden field:
+
+.. code-block:: html
+
+ <form method="post" action="/myview">
+ <input type="hidden" name="csrf_token" value="${get_csrf_token()}">
+ <input type="submit" value="Delete Everything">
+ </form>
+
+Or include it as a header in a jQuery AJAX request:
+
+.. code-block:: javascript
+
+ var csrfToken = "${get_csrf_token()}";
+ $.ajax({
+ type: "POST",
+ url: "/myview",
+ headers: { 'X-CSRF-Token': csrfToken }
+ }).done(function() {
+ alert("Deleted");
+ });
+
+The handler for the URL that receives the request should then require that the
+correct CSRF token is supplied.
+
+.. index::
+ single: csrf.new_csrf_token
+
+Using the ``csrf.new_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To explicitly create a new CSRF token, use the ``csrf.new_csrf_token()``
+method. This differs only from ``csrf.get_csrf_token()`` inasmuch as it
+clears any existing CSRF token, creates a new CSRF token, sets the token into
+the user, and returns the token.
+
+.. code-block:: python
+
+ from pyramid.csrf import new_csrf_token
+ token = new_csrf_token(request)
+
+.. note::
+
+ It is not possible to force a new CSRF token from a template. If you
+ want to regenerate your CSRF token then do it in the view code and return
+ the new token as part of the context.
+
+Checking CSRF Tokens Manually
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In request handling code, you can check the presence and validity of a CSRF
+token with :func:`pyramid.csrf.check_csrf_token`. If the token is valid, it
+will return ``True``, otherwise it will raise ``HTTPBadRequest``. Optionally,
+you can specify ``raises=False`` to have the check return ``False`` instead of
+raising an exception.
+
+By default, it checks for a POST parameter named ``csrf_token`` or a header
+named ``X-CSRF-Token``.
+
+.. code-block:: python
+
+ from pyramid.csrf import check_csrf_token
+
+ def myview(request):
+ # Require CSRF Token
+ check_csrf_token(request)
+
+ # ...
+
+.. _auto_csrf_checking:
+
+Checking CSRF Tokens Automatically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 1.7
+
+:app:`Pyramid` supports automatically checking CSRF tokens on requests with an
+unsafe method as defined by RFC2616. Any other request may be checked manually.
+This feature can be turned on globally for an application using the
+:meth:`pyramid.config.Configurator.set_default_csrf_options` directive.
+For example:
+
+.. code-block:: python
+
+ from pyramid.config import Configurator
+
+ config = Configurator()
+ config.set_default_csrf_options(require_csrf=True)
+
+CSRF checking may be explicitly enabled or disabled on a per-view basis using
+the ``require_csrf`` view option. A value of ``True`` or ``False`` will
+override the default set by ``set_default_csrf_options``. For example:
+
+.. code-block:: python
+
+ @view_config(route_name='hello', require_csrf=False)
+ def myview(request):
+ # ...
+
+When CSRF checking is active, the token and header used to find the
+supplied CSRF token will be ``csrf_token`` and ``X-CSRF-Token``, respectively,
+unless otherwise overridden by ``set_default_csrf_options``. The token is
+checked against the value in ``request.POST`` which is the submitted form body.
+If this value is not present, then the header will be checked.
+
+In addition to token based CSRF checks, if the request is using HTTPS then the
+automatic CSRF checking will also check the referrer of the request to ensure
+that it matches one of the trusted origins. By default the only trusted origin
+is the current host, however additional origins may be configured by setting
+``pyramid.csrf_trusted_origins`` to a list of domain names (and ports if they
+are non-standard). If a host in the list of domains starts with a ``.`` then
+that will allow all subdomains as well as the domain without the ``.``.
+
+If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` or
+:class:`pyramid.exceptions.BadCSRFOrigin` exception will be raised. This
+exception may be caught and handled by an :term:`exception view` but, by
+default, will result in a ``400 Bad Request`` response being sent to the
+client.
+
+Checking CSRF Tokens with a View Predicate
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. deprecated:: 1.7
+ Use the ``require_csrf`` option or read :ref:`auto_csrf_checking` instead
+ to have :class:`pyramid.exceptions.BadCSRFToken` exceptions raised.
+
+A convenient way to require a valid CSRF token for a particular view is to
+include ``check_csrf=True`` as a view predicate. See
+:meth:`pyramid.config.Configurator.add_view`.
+
+.. code-block:: python
+
+ @view_config(request_method='POST', check_csrf=True, ...)
+ def myview(request):
+ ...
+
+.. note::
+ A mismatch of a CSRF token is treated like any other predicate miss, and the
+ predicate system, when it doesn't find a view, raises ``HTTPNotFound``
+ instead of ``HTTPBadRequest``, so ``check_csrf=True`` behavior is different
+ from calling :func:`pyramid.csrf.check_csrf_token`.
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index 5b24201a9..b34d7a4f1 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -12,8 +12,7 @@ application.
This chapter describes how to configure sessions, what session implementations
:app:`Pyramid` provides out of the box, how to store and retrieve data from
-sessions, and two session-specific features: flash messages, and cross-site
-request forgery attack prevention.
+sessions, and a session-specific feature: flash messages.
.. index::
single: session factory (default)
@@ -175,10 +174,10 @@ pyramid_beaker_ Beaker_ Session factory for Pyramid
.. _PyNaCl: https://pynacl.readthedocs.io/en/latest/secret/
.. _pyramid_redis_sessions: https://pypi.python.org/pypi/pyramid_redis_sessions
-.. _Redis: http://redis.io/
+.. _Redis: https://redis.io/
.. _pyramid_beaker: https://pypi.python.org/pypi/pyramid_beaker
-.. _Beaker: http://beaker.readthedocs.org/en/latest/
+.. _Beaker: https://beaker.readthedocs.io/en/latest/
.. index::
single: session factory (custom)
@@ -316,183 +315,3 @@ flash storage.
['info message']
>>> request.session.peek_flash()
[]
-
-.. index::
- single: preventing cross-site request forgery attacks
- single: cross-site request forgery attacks, prevention
-
-Preventing Cross-Site Request Forgery Attacks
----------------------------------------------
-
-`Cross-site request forgery
-<https://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
-phenomenon whereby a user who is logged in to your website might inadvertantly
-load a URL because it is linked from, or embedded in, an attacker's website.
-If the URL is one that may modify or delete data, the consequences can be dire.
-
-You can avoid most of these attacks by issuing a unique token to the browser
-and then requiring that it be present in all potentially unsafe requests.
-:app:`Pyramid` sessions provide facilities to create and check CSRF tokens.
-
-To use CSRF tokens, you must first enable a :term:`session factory` as
-described in :ref:`using_the_default_session_factory` or
-:ref:`using_alternate_session_factories`.
-
-.. index::
- single: session.get_csrf_token
-
-Using the ``session.get_csrf_token`` Method
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To get the current CSRF token from the session, use the
-``session.get_csrf_token()`` method.
-
-.. code-block:: python
-
- token = request.session.get_csrf_token()
-
-The ``session.get_csrf_token()`` method accepts no arguments. It returns a
-CSRF *token* string. If ``session.get_csrf_token()`` or
-``session.new_csrf_token()`` was invoked previously for this session, then the
-existing token will be returned. If no CSRF token previously existed for this
-session, then a new token will be set into the session and returned. The newly
-created token will be opaque and randomized.
-
-You can use the returned token as the value of a hidden field in a form that
-posts to a method that requires elevated privileges, or supply it as a request
-header in AJAX requests.
-
-For example, include the CSRF token as a hidden field:
-
-.. code-block:: html
-
- <form method="post" action="/myview">
- <input type="hidden" name="csrf_token" value="${request.session.get_csrf_token()}">
- <input type="submit" value="Delete Everything">
- </form>
-
-Or include it as a header in a jQuery AJAX request:
-
-.. code-block:: javascript
-
- var csrfToken = ${request.session.get_csrf_token()};
- $.ajax({
- type: "POST",
- url: "/myview",
- headers: { 'X-CSRF-Token': csrfToken }
- }).done(function() {
- alert("Deleted");
- });
-
-The handler for the URL that receives the request should then require that the
-correct CSRF token is supplied.
-
-.. index::
- single: session.new_csrf_token
-
-Using the ``session.new_csrf_token`` Method
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To explicitly create a new CSRF token, use the ``session.new_csrf_token()``
-method. This differs only from ``session.get_csrf_token()`` inasmuch as it
-clears any existing CSRF token, creates a new CSRF token, sets the token into
-the session, and returns the token.
-
-.. code-block:: python
-
- token = request.session.new_csrf_token()
-
-Checking CSRF Tokens Manually
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In request handling code, you can check the presence and validity of a CSRF
-token with :func:`pyramid.session.check_csrf_token`. If the token is valid, it
-will return ``True``, otherwise it will raise ``HTTPBadRequest``. Optionally,
-you can specify ``raises=False`` to have the check return ``False`` instead of
-raising an exception.
-
-By default, it checks for a POST parameter named ``csrf_token`` or a header
-named ``X-CSRF-Token``.
-
-.. code-block:: python
-
- from pyramid.session import check_csrf_token
-
- def myview(request):
- # Require CSRF Token
- check_csrf_token(request)
-
- # ...
-
-.. _auto_csrf_checking:
-
-Checking CSRF Tokens Automatically
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. versionadded:: 1.7
-
-:app:`Pyramid` supports automatically checking CSRF tokens on requests with an
-unsafe method as defined by RFC2616. Any other request may be checked manually.
-This feature can be turned on globally for an application using the
-:meth:`pyramid.config.Configurator.set_default_csrf_options` directive.
-For example:
-
-.. code-block:: python
-
- from pyramid.config import Configurator
-
- config = Configurator()
- config.set_default_csrf_options(require_csrf=True)
-
-CSRF checking may be explicitly enabled or disabled on a per-view basis using
-the ``require_csrf`` view option. A value of ``True`` or ``False`` will
-override the default set by ``set_default_csrf_options``. For example:
-
-.. code-block:: python
-
- @view_config(route_name='hello', require_csrf=False)
- def myview(request):
- # ...
-
-When CSRF checking is active, the token and header used to find the
-supplied CSRF token will be ``csrf_token`` and ``X-CSRF-Token``, respectively,
-unless otherwise overridden by ``set_default_csrf_options``. The token is
-checked against the value in ``request.POST`` which is the submitted form body.
-If this value is not present, then the header will be checked.
-
-In addition to token based CSRF checks, if the request is using HTTPS then the
-automatic CSRF checking will also check the referrer of the request to ensure
-that it matches one of the trusted origins. By default the only trusted origin
-is the current host, however additional origins may be configured by setting
-``pyramid.csrf_trusted_origins`` to a list of domain names (and ports if they
-are non standard). If a host in the list of domains starts with a ``.`` then
-that will allow all subdomains as well as the domain without the ``.``.
-
-If CSRF checks fail then a :class:`pyramid.exceptions.BadCSRFToken` or
-:class:`pyramid.exceptions.BadCSRFOrigin` exception will be raised. This
-exception may be caught and handled by an :term:`exception view` but, by
-default, will result in a ``400 Bad Request`` response being sent to the
-client.
-
-Checking CSRF Tokens with a View Predicate
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. deprecated:: 1.7
- Use the ``require_csrf`` option or read :ref:`auto_csrf_checking` instead
- to have :class:`pyramid.exceptions.BadCSRFToken` exceptions raised.
-
-A convenient way to require a valid CSRF token for a particular view is to
-include ``check_csrf=True`` as a view predicate. See
-:meth:`pyramid.config.Configurator.add_view`.
-
-.. code-block:: python
-
- @view_config(request_method='POST', check_csrf=True, ...)
- def myview(request):
- ...
-
-.. note::
- A mismatch of a CSRF token is treated like any other predicate miss, and the
- predicate system, when it doesn't find a view, raises ``HTTPNotFound``
- instead of ``HTTPBadRequest``, so ``check_csrf=True`` behavior is different
- from calling :func:`pyramid.session.check_csrf_token`.
diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst
index cf4612602..5e7c7c871 100644
--- a/docs/narr/startup.rst
+++ b/docs/narr/startup.rst
@@ -10,12 +10,12 @@ you'll see something much like this show up on the console:
$ $VENV/bin/pserve development.ini
Starting server in PID 16305.
- Serving on http://127.0.0.1:6543
- Serving on http://[::1]:6543
+ Serving on http://localhost:6543
+ Serving on http://localhost:6543
This chapter explains what happens between the time you press the "Return" key
-on your keyboard after typing ``pserve development.ini`` and the time the line
-``serving on http://127.0.0.1:6543`` is output to your console.
+on your keyboard after typing ``pserve development.ini`` and the time the lines
+``Serving on http://localhost:6543`` are output to your console.
.. index::
single: startup process
@@ -38,7 +38,14 @@ Here's a high-level time-ordered overview of what happens when you press
begin to run and serve an application using the information contained
within the ``development.ini`` file.
-#. The framework finds a section named either ``[app:main]``,
+#. ``pserve`` passes the ``development.ini`` path to :term:`plaster` which
+ finds an available configuration loader that recognizes the ``ini`` format.
+
+#. :term:`plaster` finds the ``plaster_pastedeploy`` library which binds
+ the :term:`PasteDeploy` library and returns a parser that can understand
+ the format.
+
+#. The :term:`PasteDeploy` finds a section named either ``[app:main]``,
``[pipeline:main]``, or ``[composite:main]`` in the ``.ini`` file. This
section represents the configuration of a :term:`WSGI` application that will
be served. If you're using a simple application (e.g., ``[app:main]``), the
@@ -132,8 +139,8 @@ 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 on port 6543
- for both IPv4 and IPv6 (``listen = 127.0.0.1:6543 [::1]:6543``). The server
- code itself is what prints ``serving on http://127.0.0.1:6543``. The server
+ for both IPv4 and IPv6 (``listen = localhost:6543``). The server
+ code itself is what prints ``Serving on http://localhost:6543``. The server
serves the application, and the application is running, waiting to receive requests.
.. seealso::
diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst
index 7c847de50..b4deb42f2 100644
--- a/docs/narr/subrequest.rst
+++ b/docs/narr/subrequest.rst
@@ -62,7 +62,7 @@ object:
.. code-block:: python
:linenos:
- :emphasize-lines: 11
+ :emphasize-lines: 11,18
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 6b3b5fcce..156cb863f 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -228,6 +228,10 @@ These values are provided to the template:
provided if the template is rendered as the result of a ``renderer=``
argument to the view configuration being used.
+``get_csrf_token()``
+ A convenience function to access the current CSRF token. See
+ :ref:`get_csrf_token_in_templates` for more information.
+
``renderer_name``
The renderer name used to perform the rendering, e.g.,
``mypackage:templates/foo.pt``.
@@ -444,14 +448,14 @@ templating languages including the following:
| Mako_ | pyramid_mako_ | .mak, .mako |
+---------------------------+----------------------------+--------------------+
-.. _Chameleon: http://chameleon.readthedocs.org/en/latest/
+.. _Chameleon: https://chameleon.readthedocs.io/en/latest/
.. _pyramid_chameleon:
- http://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/
+ https://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/
.. _Jinja2: http://jinja.pocoo.org/docs/dev/
.. _pyramid_jinja2:
- http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/
+ https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/
.. _Mako: http://www.makotemplates.org/
.. _pyramid_mako:
- http://docs.pylonsproject.org/projects/pyramid-mako/en/latest/
+ https://docs.pylonsproject.org/projects/pyramid-mako/en/latest/
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 406383bbd..594badcb6 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -158,7 +158,7 @@ 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.
+statement and :func:`pyramid.testing.testConfig` to create a :term:`context manager`.
The context manager will call :func:`pyramid.testing.setUp` before the code
under test and :func:`pyramid.testing.tearDown` afterwards.
@@ -376,18 +376,16 @@ following the ``requires`` block in the file ``myproject/setup.py``.
.. literalinclude:: myproject/setup.py
:language: python
- :linenos:
- :lines: 11-22
- :lineno-start: 11
- :emphasize-lines: 8-
+ :lines: 11-23
+ :lineno-match:
+ :emphasize-lines: 9-
Remember to change the dependency.
.. literalinclude:: myproject/setup.py
:language: python
- :linenos:
- :lines: 40-44
- :lineno-start: 40
+ :lines: 42-46
+ :lineno-match:
:emphasize-lines: 2-4
As always, whenever you change your dependencies, make sure to run the correct
diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst
index 578fdeb51..406351562 100644
--- a/docs/narr/webob.rst
+++ b/docs/narr/webob.rst
@@ -27,7 +27,7 @@ functionality to the standard WebOb request, which is documented in the
:ref:`request_module` API documentation.
WebOb provides objects for HTTP requests and responses. Specifically it does
-this by wrapping the `WSGI <http://wsgi.readthedocs.org/en/latest/>`_ request
+this by wrapping the `WSGI <https://wsgi.readthedocs.io/en/latest/>`_ request
environment and response status, header list, and app_iter (body) values.
WebOb request and response objects provide many conveniences for parsing WSGI
@@ -88,7 +88,7 @@ below.
``req.urlvars`` and ``req.urlargs``
``req.urlvars`` are the keyword parameters associated with the request URL.
``req.urlargs`` are the positional parameters. These are set by products
- like `Routes <http://routes.readthedocs.org/en/latest/>`_ and `Selector
+ like `Routes <https://routes.readthedocs.io/en/latest/>`_ and `Selector
<https://github.com/lukearno/selector>`_.
Also for standard HTTP request headers, there are usually attributes such as