summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Merickel <github@m.merickel.org>2018-08-21 01:44:55 -0500
committerGitHub <noreply@github.com>2018-08-21 01:44:55 -0500
commit820a752645b460ea8009b07a75c752ab09c53dec (patch)
tree14616d81a7abedfe523c057e71ed7b2aca680754
parentdf8598a2658632f709a64e8076cce02ca49de8e6 (diff)
parent254710cb716dccfe536b20d077e3cb79be19c6b3 (diff)
downloadpyramid-820a752645b460ea8009b07a75c752ab09c53dec.tar.gz
pyramid-820a752645b460ea8009b07a75c752ab09c53dec.tar.bz2
pyramid-820a752645b460ea8009b07a75c752ab09c53dec.zip
Merge pull request #3330 from stevepiercy/docs-code-style
Docs code style
-rw-r--r--README.rst28
-rw-r--r--docs/api/request.rst38
-rw-r--r--docs/designdefense.rst122
-rw-r--r--docs/glossary.rst10
-rw-r--r--docs/index.rst10
-rw-r--r--docs/narr/advanced-features.rst20
-rw-r--r--docs/narr/advconfig.rst202
-rw-r--r--docs/narr/assets.rst282
-rw-r--r--docs/narr/commandline.rst634
-rw-r--r--docs/narr/configuration.rst66
-rw-r--r--docs/narr/environment.rst122
-rw-r--r--docs/narr/events.rst52
-rw-r--r--docs/narr/extconfig.rst190
-rw-r--r--docs/narr/extending.rst60
-rw-r--r--docs/narr/firstapp.rst6
-rw-r--r--docs/narr/hooks.rst648
-rw-r--r--docs/narr/hybrid.rst100
-rw-r--r--docs/narr/i18n.rst262
-rw-r--r--docs/narr/install.rst50
-rw-r--r--docs/narr/introduction.rst46
-rw-r--r--docs/narr/introspector.rst4
-rw-r--r--docs/narr/logging.rst6
-rw-r--r--docs/narr/project.rst168
-rw-r--r--docs/narr/renderers.rst284
-rw-r--r--docs/narr/resources.rst194
-rw-r--r--docs/narr/scaffolding.rst70
-rw-r--r--docs/narr/security.rst363
-rw-r--r--docs/narr/sessions.rst38
-rw-r--r--docs/narr/startup.rst2
-rw-r--r--docs/narr/subrequest.rst244
-rw-r--r--docs/narr/templates.rst122
-rw-r--r--docs/narr/testing.rst120
-rw-r--r--docs/narr/traversal.rst86
-rw-r--r--docs/narr/upgrading.rst52
-rw-r--r--docs/narr/urldispatch.rst460
-rw-r--r--docs/narr/vhosting.rst16
-rw-r--r--docs/narr/viewconfig.rst370
-rw-r--r--docs/narr/views.rst190
-rw-r--r--docs/narr/webob.rst28
-rw-r--r--docs/narr/zca.rst70
-rw-r--r--docs/quick_tour.rst48
-rw-r--r--docs/quick_tutorial/authentication.rst6
-rw-r--r--docs/quick_tutorial/authorization.rst12
-rw-r--r--docs/quick_tutorial/cookiecutters.rst12
-rw-r--r--docs/quick_tutorial/databases.rst72
-rw-r--r--docs/quick_tutorial/debugtoolbar.rst20
-rw-r--r--docs/quick_tutorial/forms.rst34
-rw-r--r--docs/quick_tutorial/functional_testing.rst14
-rw-r--r--docs/quick_tutorial/hello_world.rst10
-rw-r--r--docs/quick_tutorial/ini.rst16
-rw-r--r--docs/quick_tutorial/jinja2.rst20
-rw-r--r--docs/quick_tutorial/json.rst16
-rw-r--r--docs/quick_tutorial/logging.rst14
-rw-r--r--docs/quick_tutorial/more_view_classes.rst30
-rw-r--r--docs/quick_tutorial/package.rst8
-rw-r--r--docs/quick_tutorial/request_response.rst20
-rw-r--r--docs/quick_tutorial/requirements.rst44
-rw-r--r--docs/quick_tutorial/routing.rst22
-rw-r--r--docs/quick_tutorial/sessions.rst20
-rw-r--r--docs/quick_tutorial/static_assets.rst26
-rw-r--r--docs/quick_tutorial/templating.rst24
-rw-r--r--docs/quick_tutorial/tutorial_approach.rst4
-rw-r--r--docs/quick_tutorial/unit_testing.rst14
-rw-r--r--docs/quick_tutorial/view_classes.rst17
-rw-r--r--docs/quick_tutorial/views.rst18
-rw-r--r--docs/tutorials/modwsgi/index.rst40
-rw-r--r--docs/tutorials/wiki/background.rst4
-rw-r--r--docs/tutorials/wiki/definingmodels.rst6
-rw-r--r--docs/tutorials/wiki/definingviews.rst56
-rw-r--r--docs/tutorials/wiki/distributing.rst16
-rw-r--r--docs/tutorials/wiki/installation.rst72
-rw-r--r--docs/tutorials/wiki/tests.rst10
-rw-r--r--docs/tutorials/wiki2/background.rst4
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst118
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst48
-rw-r--r--docs/tutorials/wiki2/distributing.rst16
-rw-r--r--docs/tutorials/wiki2/installation.rst222
-rw-r--r--docs/tutorials/wiki2/tests.rst35
-rw-r--r--docs/typographical-conventions.rst10
-rw-r--r--docs/whatsnew-1.1.rst2
80 files changed, 3516 insertions, 3519 deletions
diff --git a/README.rst b/README.rst
index ecc8eb32f..00ec177ca 100644
--- a/README.rst
+++ b/README.rst
@@ -19,20 +19,20 @@ and deployment more fun, more predictable, and more productive.
.. code-block:: python
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
-
- def hello_world(request):
- return Response('Hello %(name)s!' % request.matchdict)
-
- if __name__ == '__main__':
- 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()
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
+
+ def hello_world(request):
+ return Response('Hello %(name)s!' % request.matchdict)
+
+ if __name__ == '__main__':
+ 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()
Pyramid is a project of the `Pylons Project <https://pylonsproject.org>`_.
diff --git a/docs/api/request.rst b/docs/api/request.rst
index 52bf50078..b5700f4ab 100644
--- a/docs/api/request.rst
+++ b/docs/api/request.rst
@@ -321,25 +321,25 @@
from the name of the ``callable``.
.. code-block:: python
- :linenos:
-
- def _connect(request):
- conn = request.registry.dbsession()
- def cleanup(request):
- # since version 1.5, request.exception is no
- # longer eagerly cleared
- if request.exception is not None:
- conn.rollback()
- else:
- conn.commit()
- conn.close()
- request.add_finished_callback(cleanup)
- return conn
-
- @subscriber(NewRequest)
- def new_request(event):
- request = event.request
- request.set_property(_connect, 'db', reify=True)
+ :linenos:
+
+ def _connect(request):
+ conn = request.registry.dbsession()
+ def cleanup(request):
+ # since version 1.5, request.exception is no
+ # longer eagerly cleared
+ if request.exception is not None:
+ conn.rollback()
+ else:
+ conn.commit()
+ conn.close()
+ request.add_finished_callback(cleanup)
+ return conn
+
+ @subscriber(NewRequest)
+ def new_request(event):
+ request = event.request
+ request.set_property(_connect, 'db', reify=True)
The subscriber doesn't actually connect to the database, it just
provides the API which, when accessed via ``request.db``, will
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index 2976dcfd5..59a064607 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -117,11 +117,11 @@ reading the code that performs a typical "unnamed utility" lookup using the
:func:`zope.component.getUtility` global API:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.interfaces import ISettings
- from zope.component import getUtility
- settings = getUtility(ISettings)
+ from pyramid.interfaces import ISettings
+ from zope.component import getUtility
+ settings = getUtility(ISettings)
After this code runs, ``settings`` will be a Python dictionary. But it's
unlikely that any civilian would know that just by reading the code. There
@@ -186,28 +186,28 @@ present in the current request or ``None`` if no userid is present in the
current request. The application developer calls it like so:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import authenticated_userid
- userid = authenticated_userid(request)
+ from pyramid.security import authenticated_userid
+ userid = authenticated_userid(request)
They now have the current user id.
Under its hood however, the implementation of ``authenticated_userid`` is this:
.. code-block:: python
- :linenos:
+ :linenos:
- def authenticated_userid(request):
- """ Return the userid of the currently authenticated user or
- ``None`` if there is no authentication policy in effect or there
- is no currently authenticated user. """
+ def authenticated_userid(request):
+ """ Return the userid of the currently authenticated user or
+ ``None`` if there is no authentication policy in effect or there
+ is no currently authenticated user. """
- registry = request.registry # the ZCA component registry
- policy = registry.queryUtility(IAuthenticationPolicy)
- if policy is None:
- return None
- return policy.authenticated_userid(request)
+ registry = request.registry # the ZCA component registry
+ policy = registry.queryUtility(IAuthenticationPolicy)
+ if policy is None:
+ return None
+ return policy.authenticated_userid(request)
Using such wrappers, we strive to always hide the ZCA API from application
developers. Application developers should just never know about the ZCA API;
@@ -263,21 +263,21 @@ In all core code, we've made use of ZCA global API functions, such as
instead of the rule. So instead of:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.interfaces import IAuthenticationPolicy
- from zope.component import getUtility
- policy = getUtility(IAuthenticationPolicy)
+ from pyramid.interfaces import IAuthenticationPolicy
+ from zope.component import getUtility
+ policy = getUtility(IAuthenticationPolicy)
:app:`Pyramid` code will usually do:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.threadlocal import get_current_registry
- registry = get_current_registry()
- policy = registry.getUtility(IAuthenticationPolicy)
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.threadlocal import get_current_registry
+ registry = get_current_registry()
+ policy = registry.getUtility(IAuthenticationPolicy)
While the latter is more verbose, it also arguably makes it more obvious what's
going on. All of the :app:`Pyramid` core code uses this pattern rather than
@@ -483,20 +483,20 @@ accept positional arguments which match information in an associated "urlconf"
such as ``r'^polls/(?P<poll_id>\d+)/$``:
.. code-block:: python
- :linenos:
+ :linenos:
- def aview(request, poll_id):
- return HttpResponse(poll_id)
+ def aview(request, poll_id):
+ return HttpResponse(poll_id)
Zope likewise allows you to add arbitrary keyword and positional arguments to
any method of a resource object found via traversal:
.. code-block:: python
- :linenos:
+ :linenos:
- from persistent import Persistent
+ from persistent import Persistent
- class MyZopeObject(Persistent):
+ class MyZopeObject(Persistent):
def aview(self, a, b, c=None):
return '%s %s %c' % (a, b, c)
@@ -1527,22 +1527,22 @@ inlined comments take into account what we've discussed in the
:ref:`microframeworks_smaller_hello_world` section.
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server # explicitly WSGI
- from pyramid.config import Configurator # to configure app registry
- from pyramid.response import Response # explicit response, no threadlocal
+ from wsgiref.simple_server import make_server # explicitly WSGI
+ from pyramid.config import Configurator # to configure app registry
+ from pyramid.response import Response # explicit response, no threadlocal
- def hello_world(request): # accept a request; no request threadlocal reqd
- # explicit response object means no response threadlocal
- return Response('Hello world!')
+ def hello_world(request): # accept a request; no request threadlocal reqd
+ # explicit response object means no response threadlocal
+ return Response('Hello world!')
- if __name__ == '__main__':
- with Configurator() as config: # no global application object
- config.add_view(hello_world) # explicit non-decorator registration
- app = config.make_wsgi_app() # explicitly WSGI
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever() # explicitly WSGI
+ if __name__ == '__main__':
+ with Configurator() as config: # no global application object
+ config.add_view(hello_world) # explicit non-decorator registration
+ app = config.make_wsgi_app() # explicitly WSGI
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever() # explicitly WSGI
Pyramid doesn't offer pluggable apps
@@ -1622,10 +1622,10 @@ reads something like this:
.. code-block:: text
- had a quick look at pyramid ... too complex to me and not really
- understand for which benefits.. I feel should consider whether it's time
- for me to step back to django .. I always hated zope (useless ?)
- complexity and I love simple way of thinking
+ had a quick look at pyramid ... too complex to me and not really
+ understand for which benefits.. I feel should consider whether it's time
+ for me to step back to django .. I always hated zope (useless ?)
+ complexity and I love simple way of thinking
(Paraphrased from a real email, actually.)
@@ -1637,21 +1637,21 @@ Too Complex
If you can understand this "hello world" program, you can use Pyramid:
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
- if __name__ == '__main__':
- 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()
+ if __name__ == '__main__':
+ 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()
Pyramid has over 1200 pages of documentation (printed), covering topics from
the very basic to the most advanced. *Nothing* is left undocumented, quite
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 043721052..b05344ae9 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -1021,12 +1021,12 @@ Glossary
A package which logs Pyramid application exception (error) information
to a standard Python logger. This add-on is most useful when
used in production applications, because the logger can be configured to
- log to a file, to UNIX syslog, to the Windows Event Log, or even to
+ log to a file, to Unix syslog, to the Windows Event Log, or even to
email. See its `documentation
<https://docs.pylonsproject.org/projects/pyramid_exclog/en/latest/>`_.
console script
- A script written to the ``bin`` (on UNIX, or ``Scripts`` on Windows)
+ A script written to the ``bin`` (on Unix, or ``Scripts`` on Windows)
directory of a Python installation or :term:`virtual environment` as the
result of running ``pip install`` or ``pip install -e .``.
@@ -1075,14 +1075,14 @@ Glossary
:class:`pyramid.interfaces.IAssetDescriptor`.
Waitress
- A :term:`WSGI` server that runs on UNIX and Windows under Python 2.7+
+ A :term:`WSGI` server that runs on Unix and Windows under Python 2.7+
and Python 3.3+. Projects generated via Pyramid cookiecutters use
Waitress as a WGSI server. See
https://docs.pylonsproject.org/projects/waitress/en/latest/ for detailed
information.
Green Unicorn
- Aka ``gunicorn``, a fast :term:`WSGI` server that runs on UNIX under
+ Aka ``gunicorn``, a fast :term:`WSGI` server that runs on Unix under
Python 2.6+ or Python 3.1+. See http://gunicorn.org/ for detailed
information.
@@ -1131,7 +1131,7 @@ Glossary
``pyvenv`` command for `creating virtual environments on Python 3.4 and
3.5
<https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments>`_,
- but it was deprecated in 3.6 in favor of ``python3 -m venv`` on UNIX or
+ but it was deprecated in 3.6 in favor of ``python3 -m venv`` on Unix or
``python -m venv`` on Windows, which is backward compatible on Python
3.3 and greater.
diff --git a/docs/index.rst b/docs/index.rst
index 3cd764b2f..36499cde4 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -85,11 +85,11 @@ the trunk via ``git``, use either command:
.. code-block:: text
- # If you have SSH keys configured on GitHub:
- git clone git@github.com:Pylons/pyramid.git
-
- # Otherwise, HTTPS will work, using your GitHub login:
- git clone https://github.com/Pylons/pyramid.git
+ # If you have SSH keys configured on GitHub:
+ git clone git@github.com:Pylons/pyramid.git
+
+ # Otherwise, HTTPS will work, using your GitHub login:
+ git clone https://github.com/Pylons/pyramid.git
To find out how to become a contributor to :app:`Pyramid`, please see `How to Contribute Source Code and Documentation <https://pylonsproject.org/community-how-to-contribute.html>`_.
diff --git a/docs/narr/advanced-features.rst b/docs/narr/advanced-features.rst
index 82e20963d..191996c27 100644
--- a/docs/narr/advanced-features.rst
+++ b/docs/narr/advanced-features.rst
@@ -92,10 +92,10 @@ For example, if you want to reuse an existing application that already has a bun
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')
+ config = Configurator()
+ config.include('pyramid_jinja2')
+ config.include('pyramid_exclog')
+ config.include('some.other.package', route_prefix='/somethingelse')
.. seealso::
@@ -262,12 +262,12 @@ You can extend :app:`Pyramid`\ 's :term:`configurator` with your own directives.
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')
+ 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:
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index bdcdf45a4..880e538f1 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -24,72 +24,72 @@ Here's a familiar example of one of the simplest :app:`Pyramid` applications,
configured imperatively:
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_view(hello_world)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
When you start this application, all will be OK. However, what happens if we
try to add another view to the configuration with the same set of
:term:`predicate` arguments as one we've already added?
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
- def goodbye_world(request):
- return Response('Goodbye world!')
+ def goodbye_world(request):
+ return Response('Goodbye world!')
- if __name__ == '__main__':
- config = Configurator()
+ if __name__ == '__main__':
+ config = Configurator()
- config.add_view(hello_world, name='hello')
+ config.add_view(hello_world, name='hello')
- # conflicting view configuration
- config.add_view(goodbye_world, name='hello')
+ # conflicting view configuration
+ config.add_view(goodbye_world, name='hello')
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
The application now has two conflicting view configuration statements. When we
try to start it again, it won't start. Instead we'll receive a traceback that
ends something like this:
.. code-block:: text
- :linenos:
-
- Traceback (most recent call last):
- File "app.py", line 12, in <module>
- app = config.make_wsgi_app()
- File "pyramid/config.py", line 839, in make_wsgi_app
- self.commit()
- File "pyramid/pyramid/config.py", line 473, in commit
- self._ctx.execute_actions()
- ... more code ...
- pyramid.exceptions.ConfigurationConflictError:
- Conflicting configuration actions
- For: ('view', None, '', None, <InterfaceClass pyramid.interfaces.IView>,
- None, None, None, None, None, False, None, None, None)
- Line 14 of file app.py in <module>: 'config.add_view(hello_world)'
- Line 17 of file app.py in <module>: 'config.add_view(goodbye_world)'
+ :linenos:
+
+ Traceback (most recent call last):
+ File "app.py", line 12, in <module>
+ app = config.make_wsgi_app()
+ File "pyramid/config.py", line 839, in make_wsgi_app
+ self.commit()
+ File "pyramid/pyramid/config.py", line 473, in commit
+ self._ctx.execute_actions()
+ ... more code ...
+ pyramid.exceptions.ConfigurationConflictError:
+ Conflicting configuration actions
+ For: ('view', None, '', None, <InterfaceClass pyramid.interfaces.IView>,
+ None, None, None, None, None, False, None, None, None)
+ Line 14 of file app.py in <module>: 'config.add_view(hello_world)'
+ Line 17 of file app.py in <module>: 'config.add_view(goodbye_world)'
This traceback is trying to tell us:
@@ -140,18 +140,18 @@ If you're getting a conflict while trying to extend an existing application,
and that application has a function which performs configuration like this one:
.. code-block:: python
- :linenos:
+ :linenos:
- def add_routes(config):
- config.add_route(...)
+ def add_routes(config):
+ config.add_route(...)
Don't call this function directly with ``config`` as an argument. Instead, use
:meth:`pyramid.config.Configurator.include`:
.. code-block:: python
- :linenos:
+ :linenos:
- config.include(add_routes)
+ config.include(add_routes)
Using :meth:`~pyramid.config.Configurator.include` instead of calling the
function directly provides a modicum of automated conflict resolution, with the
@@ -173,60 +173,60 @@ previously as the result of adding a ``commit``. Here's the application that
generates conflicts:
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
- def goodbye_world(request):
- return Response('Goodbye world!')
+ def goodbye_world(request):
+ return Response('Goodbye world!')
- if __name__ == '__main__':
- config = Configurator()
+ if __name__ == '__main__':
+ config = Configurator()
- config.add_view(hello_world, name='hello')
+ config.add_view(hello_world, name='hello')
- # conflicting view configuration
- config.add_view(goodbye_world, name='hello')
+ # conflicting view configuration
+ config.add_view(goodbye_world, name='hello')
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
We can prevent the two ``add_view`` calls from conflicting by issuing a call to
:meth:`~pyramid.config.Configurator.commit` between them:
.. code-block:: python
- :linenos:
- :emphasize-lines: 16
+ :linenos:
+ :emphasize-lines: 16
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
- def goodbye_world(request):
- return Response('Goodbye world!')
+ def goodbye_world(request):
+ return Response('Goodbye world!')
- if __name__ == '__main__':
- config = Configurator()
+ if __name__ == '__main__':
+ config = Configurator()
- config.add_view(hello_world, name='hello')
+ config.add_view(hello_world, name='hello')
- config.commit() # commit any pending configuration actions
+ config.commit() # commit any pending configuration actions
- # no-longer-conflicting view configuration
- config.add_view(goodbye_world, name='hello')
+ # no-longer-conflicting view configuration
+ config.add_view(goodbye_world, name='hello')
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
In the above example we've issued a call to
:meth:`~pyramid.config.Configurator.commit` between the two ``add_view`` calls.
@@ -249,12 +249,12 @@ You can also use a heavy hammer to circumvent conflict detection by using a
configurator constructor parameter: ``autocommit=True``. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- if __name__ == '__main__':
- config = Configurator(autocommit=True)
+ if __name__ == '__main__':
+ config = Configurator(autocommit=True)
When the ``autocommit`` parameter passed to the Configurator is ``True``,
conflict detection (and :ref:`twophase_config`) is disabled. Configuration
@@ -328,18 +328,18 @@ such a developer might factor out a function used to add routes to their
application:
.. code-block:: python
- :linenos:
+ :linenos:
- def add_routes(config):
- config.add_route(...)
+ def add_routes(config):
+ config.add_route(...)
Rather than calling this function directly with ``config`` as an argument,
instead use :meth:`pyramid.config.Configurator.include`:
.. code-block:: python
- :linenos:
+ :linenos:
- config.include(add_routes)
+ config.include(add_routes)
Using ``include`` rather than calling the function directly will allow
:ref:`automatic_conflict_resolution` to work.
@@ -348,11 +348,11 @@ Using ``include`` rather than calling the function directly will allow
as an argument:
.. code-block:: python
- :linenos:
+ :linenos:
- import myapp
+ import myapp
- config.include(myapp)
+ config.include(myapp)
For this to work properly, the ``myapp`` module must contain a callable with
the special name ``includeme``, which should perform configuration (like the
@@ -385,18 +385,18 @@ For example, the relative ordering of
non-autocommitting configurator is used. This code snippet:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_view('some.view', renderer='path_to_custom/renderer.rn')
- config.add_renderer('.rn', SomeCustomRendererFactory)
+ config.add_view('some.view', renderer='path_to_custom/renderer.rn')
+ config.add_renderer('.rn', SomeCustomRendererFactory)
Has the same result as:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_renderer('.rn', SomeCustomRendererFactory)
- config.add_view('some.view', renderer='path_to_custom/renderer.rn')
+ config.add_renderer('.rn', SomeCustomRendererFactory)
+ config.add_view('some.view', renderer='path_to_custom/renderer.rn')
Even though the view statement depends on the registration of a custom
renderer, due to two-phase configuration, the order in which the configuration
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index f5a2f9684..2b0b90b4a 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -51,10 +51,10 @@ might address the asset using the :term:`asset specification`
inside a ``myapp`` package:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render_to_response
- render_to_response('myapp:templates/some_template.pt', {}, request)
+ from pyramid.renderers import render_to_response
+ render_to_response('myapp:templates/some_template.pt', {}, request)
"Under the hood", when this API is called, :app:`Pyramid` attempts to make
sense out of the string ``myapp:templates/some_template.pt`` provided by the
@@ -114,10 +114,10 @@ from the ``/var/www/static`` directory of the computer which runs the
:app:`Pyramid` application as URLs beneath the ``/static`` URL prefix.
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='/var/www/static')
+ # config is an instance of pyramid.config.Configurator
+ config.add_static_view(name='static', path='/var/www/static')
The ``name`` represents a URL *prefix*. In order for files that live in the
``path`` directory to be served, a URL that requests one of them must begin
@@ -153,10 +153,10 @@ named ``some_package``, we can use a fully qualified :term:`asset
specification` as the ``path``:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='some_package:a/b/c/static')
+ # config is an instance of pyramid.config.Configurator
+ config.add_static_view(name='static', path='some_package:a/b/c/static')
The ``path`` provided to :meth:`~pyramid.config.Configurator.add_static_view`
may be a fully qualified :term:`asset specification` or an *absolute path*.
@@ -173,11 +173,11 @@ For example, :meth:`~pyramid.config.Configurator.add_static_view` may be fed a
``name`` argument which is ``http://example.com/images``:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='http://example.com/images',
- path='mypackage:images')
+ # config is an instance of pyramid.config.Configurator
+ config.add_static_view(name='http://example.com/images',
+ path='mypackage:images')
Because :meth:`~pyramid.config.Configurator.add_static_view` is provided with a
``name`` argument that is the URL ``http://example.com/images``, subsequent
@@ -208,10 +208,10 @@ static registration ``path`` attribute.
For example, let's assume you create a set of static declarations like so:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_static_view(name='static1', path='mypackage:assets/1')
- config.add_static_view(name='static2', path='mypackage:assets/2')
+ config.add_static_view(name='static1', path='mypackage:assets/1')
+ config.add_static_view(name='static2', path='mypackage:assets/2')
These declarations create URL-accessible directories which have URLs that begin
with ``/static1`` and ``/static2``, respectively. The assets in the
@@ -225,16 +225,16 @@ configuration. Instead, use the :meth:`~pyramid.request.Request.static_url`
API to generate them for you. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render_to_response
+ from pyramid.renderers import render_to_response
- def my_view(request):
- css_url = request.static_url('mypackage:assets/1/foo.css')
- js_url = request.static_url('mypackage:assets/2/foo.js')
- return render_to_response('templates/my_template.pt',
- dict(css_url=css_url, js_url=js_url),
- request=request)
+ def my_view(request):
+ css_url = request.static_url('mypackage:assets/1/foo.css')
+ js_url = request.static_url('mypackage:assets/2/foo.js')
+ return render_to_response('templates/my_template.pt',
+ dict(css_url=css_url, js_url=js_url),
+ request=request)
If the request "application URL" of the running system is
``http://example.com``, the ``css_url`` generated above would be:
@@ -254,9 +254,9 @@ a *URL* instead of a view name. For example, the ``name`` argument may be
``http://example.com`` while the ``path`` given may be ``mypackage:images``:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_static_view(name='http://example.com/images',
+ config.add_static_view(name='http://example.com/images',
path='mypackage:images')
Under such a configuration, the URL generated by ``static_url`` for assets
@@ -264,10 +264,10 @@ which begin with ``mypackage:images`` will be prefixed with
``http://example.com/images``:
.. code-block:: python
- :linenos:
+ :linenos:
- request.static_url('mypackage:images/logo.png')
- # -> http://example.com/images/logo.png
+ request.static_url('mypackage:images/logo.png')
+ # -> http://example.com/images/logo.png
Using :meth:`~pyramid.request.Request.static_url` in conjunction with a
:meth:`~pyramid.config.Configurator.add_static_view` makes it possible to put
@@ -282,23 +282,23 @@ named ``media_location`` which we can set to an external URL in production when
our assets are hosted on a CDN.
.. code-block:: python
- :linenos:
+ :linenos:
- media_location = settings.get('media_location', 'static')
+ media_location = settings.get('media_location', 'static')
- config = Configurator(settings=settings)
- config.add_static_view(path='myapp:static', name=media_location)
+ config = Configurator(settings=settings)
+ config.add_static_view(path='myapp:static', name=media_location)
Now we can optionally define the setting in our ini file:
.. code-block:: ini
- :linenos:
+ :linenos:
- # production.ini
- [app:main]
- use = egg:myapp#main
+ # production.ini
+ [app:main]
+ use = egg:myapp#main
- media_location = http://static.example.com/
+ media_location = http://static.example.com/
It is also possible to serve assets that live outside of the source by
referring to an absolute path on the filesystem. There are two ways to
@@ -320,9 +320,9 @@ absolute path.
.. code-block:: python
- config.add_static_view(path='myapp:static_images', name='static')
- config.override_asset(to_override='myapp:static_images/',
- override_with='/abs/path/to/images/')
+ config.add_static_view(path='myapp:static_images', name='static')
+ config.override_asset(to_override='myapp:static_images/',
+ override_with='/abs/path/to/images/')
From this configuration it is now possible to use
:meth:`~pyramid.request.Request.static_url` to generate URLs to the data in the
@@ -369,25 +369,25 @@ resource's old URL.
assets using :meth:`~pyramid.config.Configurator.add_cache_buster`:
.. code-block:: python
- :linenos:
+ :linenos:
- import time
- from pyramid.static import QueryStringConstantCacheBuster
+ import time
+ from pyramid.static import QueryStringConstantCacheBuster
- # config is an instance of pyramid.config.Configurator
- config.add_static_view(name='static', path='mypackage:folder/static/')
- config.add_cache_buster(
- 'mypackage:folder/static/',
- QueryStringConstantCacheBuster(str(int(time.time()))))
+ # config is an instance of pyramid.config.Configurator
+ config.add_static_view(name='static', path='mypackage:folder/static/')
+ config.add_cache_buster(
+ 'mypackage:folder/static/',
+ QueryStringConstantCacheBuster(str(int(time.time()))))
Adding the cachebuster instructs :app:`Pyramid` to add the current time for
a static asset to the query string in the asset's URL:
.. code-block:: python
- :linenos:
+ :linenos:
- js_url = request.static_url('mypackage:folder/static/js/myapp.js')
- # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121'
+ js_url = request.static_url('mypackage:folder/static/js/myapp.js')
+ # Returns: 'http://www.example.com/static/js/myapp.js?x=1445318121'
When the web server restarts, the time constant will change and therefore so
will its URL.
@@ -434,45 +434,45 @@ way the asset token is generated. To do this just subclass
the hash of the current commit:
.. code-block:: python
- :linenos:
-
- import os
- import subprocess
- from pyramid.static import QueryStringCacheBuster
-
- class GitCacheBuster(QueryStringCacheBuster):
- """
- Assuming your code is installed as a Git checkout, as opposed to an egg
- from an egg repository like PYPI, you can use this cachebuster to get
- the current commit's SHA1 to use as the cache bust token.
- """
- def __init__(self, param='x', repo_path=None):
- super(GitCacheBuster, self).__init__(param=param)
- if repo_path is None:
- repo_path = os.path.dirname(os.path.abspath(__file__))
- self.sha1 = subprocess.check_output(
- ['git', 'rev-parse', 'HEAD'],
- cwd=repo_path).strip()
-
- def tokenize(self, pathspec):
- return self.sha1
+ :linenos:
+
+ import os
+ import subprocess
+ from pyramid.static import QueryStringCacheBuster
+
+ class GitCacheBuster(QueryStringCacheBuster):
+ """
+ Assuming your code is installed as a Git checkout, as opposed to an egg
+ from an egg repository like PYPI, you can use this cachebuster to get
+ the current commit's SHA1 to use as the cache bust token.
+ """
+ def __init__(self, param='x', repo_path=None):
+ super(GitCacheBuster, self).__init__(param=param)
+ if repo_path is None:
+ repo_path = os.path.dirname(os.path.abspath(__file__))
+ self.sha1 = subprocess.check_output(
+ ['git', 'rev-parse', 'HEAD'],
+ cwd=repo_path).strip()
+
+ def tokenize(self, pathspec):
+ return self.sha1
A simple cache buster that modifies the path segment can be constructed as
well:
.. code-block:: python
- :linenos:
+ :linenos:
- import posixpath
+ import posixpath
- class PathConstantCacheBuster(object):
- def __init__(self, token):
- self.token = token
+ class PathConstantCacheBuster(object):
+ def __init__(self, token):
+ self.token = token
- def __call__(self, request, subpath, kw):
- base_subpath, ext = posixpath.splitext(subpath)
- new_subpath = base_subpath + self.token + ext
- return new_subpath, kw
+ def __call__(self, request, subpath, kw):
+ base_subpath, ext = posixpath.splitext(subpath)
+ new_subpath = base_subpath + self.token + ext
+ return new_subpath, kw
The caveat with this approach is that modifying the path segment
changes the file name, and thus must match what is actually on the
@@ -512,25 +512,25 @@ Assuming an example ``manifest.json`` like:
.. code-block:: json
- {
- "css/main.css": "css/main-678b7c80.css",
- "images/background.png": "images/background-a8169106.png"
- }
+ {
+ "css/main.css": "css/main-678b7c80.css",
+ "images/background.png": "images/background-a8169106.png"
+ }
The following code would set up a cachebuster:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.static import ManifestCacheBuster
+ from pyramid.static import ManifestCacheBuster
- config.add_static_view(
- name='http://mycdn.example.com/',
- path='mypackage:static')
+ config.add_static_view(
+ name='http://mycdn.example.com/',
+ path='mypackage:static')
- config.add_cache_buster(
- 'mypackage:static/',
- ManifestCacheBuster('myapp:static/manifest.json'))
+ config.add_cache_buster(
+ 'mypackage:static/',
+ ManifestCacheBuster('myapp:static/manifest.json'))
It's important to note that the cache buster only handles generating
cache-busted URLs for static assets. It does **NOT** provide any solutions for
@@ -624,10 +624,10 @@ root that exists at the end of your routing table, create an instance of the
application root as below.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.static import static_view
- static_view = static_view('/path/to/static/dir', use_subpath=True)
+ from pyramid.static import static_view
+ static_view = static_view('/path/to/static/dir', use_subpath=True)
.. note::
@@ -641,13 +641,13 @@ accessible as ``/<filename>`` using a configuration method in your
application's startup code.
.. code-block:: python
- :linenos:
+ :linenos:
- # .. every other add_route declaration should come
- # before this one, as it will, by default, catch all requests
+ # .. every other add_route declaration should come
+ # before this one, as it will, by default, catch all requests
- config.add_route('catchall_static', '/*subpath')
- config.add_view('myapp.static.static_view', route_name='catchall_static')
+ config.add_route('catchall_static', '/*subpath')
+ config.add_view('myapp.static.static_view', route_name='catchall_static')
The special name ``*subpath`` above is used by the
:class:`~pyramid.static.static_view` view callable to signify the path of the
@@ -660,15 +660,15 @@ You can register a simple view callable to serve a single static asset. To do
so, do things "by hand". First define the view callable.
.. code-block:: python
- :linenos:
+ :linenos:
- import os
- from pyramid.response import FileResponse
+ import os
+ from pyramid.response import FileResponse
- def favicon_view(request):
- here = os.path.dirname(__file__)
- icon = os.path.join(here, 'static', 'favicon.ico')
- return FileResponse(icon, request=request)
+ def favicon_view(request):
+ here = os.path.dirname(__file__)
+ icon = os.path.join(here, 'static', 'favicon.ico')
+ return FileResponse(icon, request=request)
The above bit of code within ``favicon_view`` computes "here", which is a path
relative to the Python file in which the function is defined. It then creates
@@ -682,17 +682,17 @@ You might register such a view via configuration as a view callable that should
be called as the result of a traversal:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_view('myapp.views.favicon_view', name='favicon.ico')
+ config.add_view('myapp.views.favicon_view', name='favicon.ico')
Or you might register it to be the view callable for a particular route:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('favicon', '/favicon.ico')
- config.add_view('myapp.views.favicon_view', route_name='favicon')
+ config.add_route('favicon', '/favicon.ico')
+ config.add_view('myapp.views.favicon_view', route_name='favicon')
Because this is a simple view callable, it can be protected with a
:term:`permission` or can be configured to respond under different
@@ -750,11 +750,11 @@ An individual call to :meth:`~pyramid.config.Configurator.override_asset` can
override a single asset. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- config.override_asset(
- to_override='some.package:templates/mytemplate.pt',
- override_with='another.package:othertemplates/anothertemplate.pt')
+ config.override_asset(
+ to_override='some.package:templates/mytemplate.pt',
+ override_with='another.package:othertemplates/anothertemplate.pt')
The string value passed to both ``to_override`` and ``override_with`` sent to
the ``override_asset`` API is called an :term:`asset specification`. The colon
@@ -764,17 +764,17 @@ specified, the override attempts to resolve every lookup into a package from
the directory of another package. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- config.override_asset(to_override='some.package',
- override_with='another.package')
+ config.override_asset(to_override='some.package',
+ override_with='another.package')
Individual subdirectories within a package can also be overridden:
.. code-block:: python
- :linenos:
+ :linenos:
- config.override_asset(to_override='some.package:templates/',
+ config.override_asset(to_override='some.package:templates/',
override_with='another.package:othertemplates/')
If you wish to override a directory with another directory, you *must* make
@@ -798,10 +798,10 @@ resides (or the ``package`` argument to the
:class:`~pyramid.config.Configurator` class construction). For example:
.. code-block:: python
- :linenos:
+ :linenos:
- config.override_asset(to_override='.subpackage:templates/',
- override_with='another.package:templates/')
+ config.override_asset(to_override='.subpackage:templates/',
+ override_with='another.package:templates/')
Multiple calls to ``override_asset`` which name a shared ``to_override`` but a
different ``override_with`` specification can be "stacked" to form a search
@@ -841,25 +841,25 @@ manifest, and the new assets served by their own cache buster. To do this,
option. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.static import ManifestCacheBuster
+ from pyramid.static import ManifestCacheBuster
- # define a static view for myapp:static assets
- config.add_static_view('static', 'myapp:static')
+ # define a static view for myapp:static assets
+ config.add_static_view('static', 'myapp:static')
- # setup a cache buster for your app based on the myapp:static assets
- my_cb = ManifestCacheBuster('myapp:static/manifest.json')
- config.add_cache_buster('myapp:static', my_cb)
+ # setup a cache buster for your app based on the myapp:static assets
+ my_cb = ManifestCacheBuster('myapp:static/manifest.json')
+ config.add_cache_buster('myapp:static', my_cb)
- # override an asset
- config.override_asset(
- to_override='myapp:static/background.png',
- override_with='theme:static/background.png')
+ # override an asset
+ config.override_asset(
+ to_override='myapp:static/background.png',
+ override_with='theme:static/background.png')
- # override the cache buster for theme:static assets
- theme_cb = ManifestCacheBuster('theme:static/manifest.json')
- config.add_cache_buster('theme:static', theme_cb, explicit=True)
+ # override the cache buster for theme:static assets
+ theme_cb = ManifestCacheBuster('theme:static/manifest.json')
+ config.add_cache_buster('theme:static', theme_cb, explicit=True)
In the above example there is a default cache buster, ``my_cb``, for all
assets served from the ``myapp:static`` folder. This would also affect
diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst
index d0c1e6edd..9e0310c29 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -32,19 +32,19 @@ to be ``main``.
Here is an example for a simple view configuration using :term:`traversal`:
.. code-block:: text
- :linenos:
+ :linenos:
- $ $VENV/bin/pviews development.ini#tutorial /FrontPage
+ $VENV/bin/pviews development.ini#tutorial /FrontPage
- URL = /FrontPage
+ URL = /FrontPage
- context: <tutorial.models.Page object at 0xa12536c>
- view name:
+ context: <tutorial.models.Page object at 0xa12536c>
+ view name:
- View:
- -----
- tutorial.views.view_page
- required permission = view
+ View:
+ -----
+ tutorial.views.view_page
+ required permission = view
The output always has the requested URL at the top and below that all the views
that matched with their view configuration details. In this example only one
@@ -55,48 +55,48 @@ permissions and predicates that are part of that view configuration.
A more complex configuration might generate something like this:
.. code-block:: text
- :linenos:
-
- $ $VENV/bin/pviews development.ini#shootout /about
-
- URL = /about
-
- context: <shootout.models.RootFactory object at 0xa56668c>
- view name: about
-
- Route:
- ------
- route name: about
- route pattern: /about
- route path: /about
- subpath:
- route predicates (request method = GET)
-
- View:
- -----
- shootout.views.about_view
- required permission = view
- view predicates (request_param testing, header X/header)
-
- Route:
- ------
- route name: about_post
- route pattern: /about
- route path: /about
- subpath:
- route predicates (request method = POST)
-
- View:
- -----
- shootout.views.about_view_post
- required permission = view
- view predicates (request_param test)
-
- View:
- -----
- shootout.views.about_view_post2
- required permission = view
- view predicates (request_param test2)
+ :linenos:
+
+ $VENV/bin/pviews development.ini#shootout /about
+
+ URL = /about
+
+ context: <shootout.models.RootFactory object at 0xa56668c>
+ view name: about
+
+ Route:
+ ------
+ route name: about
+ route pattern: /about
+ route path: /about
+ subpath:
+ route predicates (request method = GET)
+
+ View:
+ -----
+ shootout.views.about_view
+ required permission = view
+ view predicates (request_param testing, header X/header)
+
+ Route:
+ ------
+ route name: about_post
+ route pattern: /about
+ route path: /about
+ subpath:
+ route predicates (request method = POST)
+
+ View:
+ -----
+ shootout.views.about_view_post
+ required permission = view
+ view predicates (request_param test)
+
+ View:
+ -----
+ shootout.views.about_view_post2
+ required permission = view
+ view predicates (request_param test2)
In this case, we are dealing with a :term:`URL dispatch` application. This
specific URL has two matching routes. The matching route information is
@@ -131,22 +131,22 @@ points to your application. For example, your application ``.ini`` file might
have an ``[app:main]`` section that looks like so:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyProject
- pyramid.reload_templates = true
- pyramid.debug_authorization = false
- pyramid.debug_notfound = false
- pyramid.debug_templates = true
- pyramid.default_locale_name = en
+ [app:main]
+ use = egg:MyProject
+ pyramid.reload_templates = true
+ pyramid.debug_authorization = false
+ pyramid.debug_notfound = false
+ pyramid.debug_templates = true
+ pyramid.default_locale_name = en
If so, you can use the following command to invoke a debug shell using the name
``main`` as a section name:
.. code-block:: text
- $ $VENV/bin/pshell starter/development.ini#main
+ $VENV/bin/pshell starter/development.ini#main
Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32)
[GCC 4.4.3] on linux2
Type "help" for more information.
@@ -180,7 +180,7 @@ hash after the filename:
.. code-block:: text
- $ $VENV/bin/pshell starter/development.ini
+ $VENV/bin/pshell starter/development.ini
Press ``Ctrl-D`` to exit the interactive shell (or ``Ctrl-Z`` on Windows).
@@ -213,11 +213,11 @@ using ``pyramid_tm`` to configure a transaction manager on the request as
``request.tm``.
.. code-block:: ini
- :linenos:
+ :linenos:
- [pshell]
- setup = myapp.lib.pshell.setup
- models = myapp.models
+ [pshell]
+ setup = myapp.lib.pshell.setup
+ models = myapp.models
By defining the ``setup`` callable, we will create the module ``myapp.lib.pshell`` containing a callable named ``setup`` that will receive the global environment before it is exposed to the shell. Here we mutate the environment's request as well as add a new value containing a WebTest version of the application to which we can easily submit requests. The ``setup`` callable can also be a generator which can wrap the entire shell lifecycle, executing code when the shell exits.
@@ -254,7 +254,7 @@ When this ``.ini`` file is loaded, the extra variable ``models`` will be availab
.. code-block:: text
- $ $VENV/bin/pshell starter/development.ini
+ $VENV/bin/pshell starter/development.ini
Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32)
[GCC 4.4.3] on linux2
Type "help" for more information.
@@ -298,17 +298,17 @@ used. You may also specifically invoke your choice with the ``-p choice`` or
.. code-block:: text
- $ $VENV/bin/pshell -p ipython development.ini#MyProject
+ $VENV/bin/pshell -p ipython development.ini#MyProject
You may use the ``--list-shells`` option to see the available shells.
.. code-block:: text
- $ $VENV/bin/pshell --list-shells
- Available shells:
- bpython
- ipython
- python
+ $VENV/bin/pshell --list-shells
+ Available shells:
+ bpython
+ ipython
+ python
If you want to use a shell that isn't supported out of the box, you can
introduce a new shell by registering an entry point in your ``setup.py``:
@@ -318,7 +318,7 @@ introduce a new shell by registering an entry point in your ``setup.py``:
setup(
entry_points={
'pyramid.pshell_runner': [
- 'myshell=my_app:ptpython_shell_factory',
+ 'myshell=my_app:ptpython_shell_factory',
],
},
)
@@ -349,10 +349,10 @@ You may use the ``default_shell`` option in your ``[pshell]`` ini section to
specify a list of preferred shells.
.. code-block:: ini
- :linenos:
+ :linenos:
- [pshell]
- default_shell = ptpython ipython bpython
+ [pshell]
+ default_shell = ptpython ipython bpython
.. versionadded:: 1.6
@@ -379,21 +379,21 @@ the ``section_name`` is ``main`` and can be omitted.
For example:
.. code-block:: text
- :linenos:
-
- $ $VENV/bin/proutes development.ini
- Name Pattern View Method
- ---- ------- ---- ------
- debugtoolbar /_debug_toolbar/*subpath <wsgiapp> *
- __static/ /static/*subpath dummy_starter:static/ *
- __static2/ /static2/*subpath /var/www/static/ *
- __pdt_images/ /pdt_images/*subpath pyramid_debugtoolbar:static/img/ *
- a / <unknown> *
- no_view_attached / <unknown> *
- route_and_view_attached / app1.standard_views.route_and_view_attached *
- method_conflicts /conflicts app1.standard_conflicts <route mismatch>
- multiview /multiview app1.standard_views.multiview GET,PATCH
- not_post /not_post app1.standard_views.multview !POST,*
+ :linenos:
+
+ $VENV/bin/proutes development.ini
+ Name Pattern View Method
+ ---- ------- ---- ------
+ debugtoolbar /_debug_toolbar/*subpath <wsgiapp> *
+ __static/ /static/*subpath dummy_starter:static/ *
+ __static2/ /static2/*subpath /var/www/static/ *
+ __pdt_images/ /pdt_images/*subpath pyramid_debugtoolbar:static/img/ *
+ a / <unknown> *
+ no_view_attached / <unknown> *
+ route_and_view_attached / app1.standard_views.route_and_view_attached *
+ method_conflicts /conflicts app1.standard_conflicts <route mismatch>
+ multiview /multiview app1.standard_views.multiview GET,PATCH
+ not_post /not_post app1.standard_views.multview !POST,*
``proutes`` generates a table with four columns: *Name*, *Pattern*, *View*, and
*Method*. The items listed in the Name column are route names, the items
@@ -416,7 +416,7 @@ and use those as defaults.
For example you may remove the request method and place the view first:
.. code-block:: text
- :linenos:
+ :linenos:
[proutes]
format = view
@@ -426,7 +426,7 @@ For example you may remove the request method and place the view first:
You can also separate the formats with commas or spaces:
.. code-block:: text
- :linenos:
+ :linenos:
[proutes]
format = view name pattern
@@ -463,67 +463,67 @@ For example, here's the ``ptweens`` command run against a system configured
without any explicit tweens:
.. code-block:: text
- :linenos:
+ :linenos:
- $ $VENV/bin/ptweens development.ini
- "pyramid.tweens" config value NOT set (implicitly ordered tweens used)
+ $VENV/bin/ptweens development.ini
+ "pyramid.tweens" config value NOT set (implicitly ordered tweens used)
- Implicit Tween Chain
+ Implicit Tween Chain
- Position Name Alias
- -------- ---- -----
- - - INGRESS
- 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory pdbt
- 1 pyramid.tweens.excview_tween_factory excview
- - - MAIN
+ Position Name Alias
+ -------- ---- -----
+ - - INGRESS
+ 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory pdbt
+ 1 pyramid.tweens.excview_tween_factory excview
+ - - MAIN
Here's the ``ptweens`` command run against a system configured *with* explicit
tweens defined in its ``development.ini`` file:
.. code-block:: text
- :linenos:
+ :linenos:
- $ ptweens development.ini
- "pyramid.tweens" config value set (explicitly ordered tweens used)
+ ptweens development.ini
+ "pyramid.tweens" config value set (explicitly ordered tweens used)
- Explicit Tween Chain (used)
+ Explicit Tween Chain (used)
- Position Name
- -------- ----
- - INGRESS
- 0 starter.tween_factory2
- 1 starter.tween_factory1
- 2 pyramid.tweens.excview_tween_factory
- - MAIN
+ Position Name
+ -------- ----
+ - INGRESS
+ 0 starter.tween_factory2
+ 1 starter.tween_factory1
+ 2 pyramid.tweens.excview_tween_factory
+ - MAIN
- Implicit Tween Chain (not used)
+ Implicit Tween Chain (not used)
- Position Name
- -------- ----
- - INGRESS
- 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory
- 1 pyramid.tweens.excview_tween_factory
- - MAIN
+ Position Name
+ -------- ----
+ - INGRESS
+ 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory
+ 1 pyramid.tweens.excview_tween_factory
+ - MAIN
Here's the application configuration section of the ``development.ini`` used by
the above ``ptweens`` command which reports that the explicit tween chain is
used:
.. code-block:: ini
- :linenos:
-
- [app:main]
- use = egg:starter
- reload_templates = true
- debug_authorization = false
- debug_notfound = false
- debug_routematch = false
- debug_templates = true
- default_locale_name = en
- pyramid.include = pyramid_debugtoolbar
- pyramid.tweens = starter.tween_factory2
- starter.tween_factory1
- pyramid.tweens.excview_tween_factory
+ :linenos:
+
+ [app:main]
+ use = egg:starter
+ reload_templates = true
+ debug_authorization = false
+ debug_notfound = false
+ debug_routematch = false
+ debug_templates = true
+ default_locale_name = en
+ pyramid.include = pyramid_debugtoolbar
+ pyramid.tweens = starter.tween_factory2
+ starter.tween_factory1
+ pyramid.tweens.excview_tween_factory
See :ref:`registering_tweens` for more information about tweens.
@@ -676,10 +676,10 @@ representing your Pyramid application's configuration as a single argument:
.. code-block:: python
- from pyramid.paster import bootstrap
+ from pyramid.paster import bootstrap
- with bootstrap('/path/to/my/development.ini') as env:
- print(env['request'].route_url('home'))
+ with bootstrap('/path/to/my/development.ini') as env:
+ print(env['request'].route_url('home'))
:func:`pyramid.paster.bootstrap` returns a dictionary containing
framework-related information. This dictionary will always contain a
@@ -719,17 +719,17 @@ above looks like so:
.. code-block:: ini
- [pipeline:main]
- pipeline = translogger
- another
+ [pipeline:main]
+ pipeline = translogger
+ another
- [filter:translogger]
- filter_app_factory = egg:Paste#translogger
- setup_console_handler = False
- logger_name = wsgi
+ [filter:translogger]
+ filter_app_factory = egg:Paste#translogger
+ setup_console_handler = False
+ logger_name = wsgi
- [app:another]
- use = egg:MyProject
+ [app:another]
+ use = egg:MyProject
The configuration loaded by the above bootstrap example will use the
configuration implied by the ``[pipeline:main]`` section of your configuration
@@ -744,10 +744,10 @@ load instead of ``main``:
.. code-block:: python
- from pyramid.paster import bootstrap
+ from pyramid.paster import bootstrap
- with bootstrap('/path/to/my/development.ini#another') as env:
- print(env['request'].route_url('home'))
+ with bootstrap('/path/to/my/development.ini#another') as env:
+ print(env['request'].route_url('home'))
The above example specifies the ``another`` ``app``, ``pipeline``, or
``composite`` section of your PasteDeploy configuration file. The ``app``
@@ -769,7 +769,7 @@ Assuming that you have a route configured in your application like so:
.. code-block:: python
- config.add_route('verify', '/verify/{code}')
+ config.add_route('verify', '/verify/{code}')
You need to inform the Pyramid environment that the WSGI application is
handling requests from a certain base. For example, we want to simulate
@@ -780,20 +780,20 @@ desired request and passing it into :func:`~pyramid.paster.bootstrap`:
.. code-block:: python
- from pyramid.paster import bootstrap
- from pyramid.request import Request
+ from pyramid.paster import bootstrap
+ from pyramid.request import Request
- request = Request.blank('/', base_url='https://example.com/prefix')
- with bootstrap('/path/to/my/development.ini#another', request=request) as env:
- print(env['request'].application_url)
- # will print 'https://example.com/prefix'
+ request = Request.blank('/', base_url='https://example.com/prefix')
+ with bootstrap('/path/to/my/development.ini#another', request=request) as env:
+ print(env['request'].application_url)
+ # will print 'https://example.com/prefix'
Now you can readily use Pyramid's APIs for generating URLs:
.. code-block:: python
- env['request'].route_url('verify', code='1337')
- # will return 'https://example.com/prefix/verify/1337'
+ env['request'].route_url('verify', code='1337')
+ # will return 'https://example.com/prefix/verify/1337'
Cleanup
@@ -806,12 +806,12 @@ callback:
.. code-block:: python
- from pyramid.paster import bootstrap
- env = bootstrap('/path/to/my/development.ini')
+ from pyramid.paster import bootstrap
+ env = bootstrap('/path/to/my/development.ini')
- # .. do stuff ...
+ # .. do stuff ...
- env['closer']()
+ env['closer']()
Setting Up Logging
@@ -824,8 +824,8 @@ use the following command:
.. code-block:: python
- import pyramid.paster
- pyramid.paster.setup_logging('/path/to/my/development.ini')
+ import pyramid.paster
+ pyramid.paster.setup_logging('/path/to/my/development.ini')
See :ref:`logging_chapter` for more information on logging within
:app:`Pyramid`.
@@ -878,50 +878,50 @@ Within this package, we'll pretend you've added a ``scripts.py`` module which
contains the following code:
.. code-block:: python
- :linenos:
-
- # myproject.scripts module
-
- import optparse
- import sys
- import textwrap
-
- from pyramid.paster import bootstrap
-
- def settings_show():
- description = """\
- Print the deployment settings for a Pyramid application. Example:
- 'show_settings deployment.ini'
- """
- usage = "usage: %prog config_uri"
- parser = optparse.OptionParser(
- usage=usage,
- description=textwrap.dedent(description)
- )
- parser.add_option(
- '-o', '--omit',
- dest='omit',
- metavar='PREFIX',
- type='string',
- action='append',
- help=("Omit settings which start with PREFIX (you can use this "
- "option multiple times)")
- )
-
- options, args = parser.parse_args(sys.argv[1:])
- if not len(args) >= 1:
- print('You must provide at least one argument')
- return 2
- config_uri = args[0]
- omit = options.omit
- if omit is None:
- omit = []
- with bootstrap(config_uri) as env:
- settings = env['registry'].settings
- for k, v in settings.items():
- if any([k.startswith(x) for x in omit]):
- continue
- print('%-40s %-20s' % (k, v))
+ :linenos:
+
+ # myproject.scripts module
+
+ import optparse
+ import sys
+ import textwrap
+
+ from pyramid.paster import bootstrap
+
+ def settings_show():
+ description = """\
+ Print the deployment settings for a Pyramid application. Example:
+ 'show_settings deployment.ini'
+ """
+ usage = "usage: %prog config_uri"
+ parser = optparse.OptionParser(
+ usage=usage,
+ description=textwrap.dedent(description)
+ )
+ parser.add_option(
+ '-o', '--omit',
+ dest='omit',
+ metavar='PREFIX',
+ type='string',
+ action='append',
+ help=("Omit settings which start with PREFIX (you can use this "
+ "option multiple times)")
+ )
+
+ options, args = parser.parse_args(sys.argv[1:])
+ if not len(args) >= 1:
+ print('You must provide at least one argument')
+ return 2
+ config_uri = args[0]
+ omit = options.omit
+ if omit is None:
+ omit = []
+ with bootstrap(config_uri) as env:
+ settings = env['registry'].settings
+ for k, v in settings.items():
+ if any([k.startswith(x) for x in omit]):
+ continue
+ print('%-40s %-20s' % (k, v))
This script uses the Python ``optparse`` module to allow us to make sense out
of extra arguments passed to the script. It uses the
@@ -934,52 +934,52 @@ distribution's ``setup.py`` about its existence. Within your distribution's
top-level directory, your ``setup.py`` file will look something like this:
.. code-block:: python
- :linenos:
-
- import os
-
- from setuptools import setup, find_packages
-
- here = os.path.abspath(os.path.dirname(__file__))
- with open(os.path.join(here, 'README.txt')) as f:
- README = f.read()
- with open(os.path.join(here, 'CHANGES.txt')) as f:
- CHANGES = f.read()
-
- requires = ['pyramid', 'pyramid_debugtoolbar']
-
- tests_require = [
- 'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
- 'pytest-cov',
- ]
-
- setup(name='MyProject',
- version='0.0',
- description='My project',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pyramid pylons',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=requires,
- extras_require={
- 'testing': tests_require,
- },
- entry_points = """\
- [paste.app_factory]
- main = myproject:main
- """,
- )
+ :linenos:
+
+ import os
+
+ from setuptools import setup, find_packages
+
+ here = os.path.abspath(os.path.dirname(__file__))
+ with open(os.path.join(here, 'README.txt')) as f:
+ README = f.read()
+ with open(os.path.join(here, 'CHANGES.txt')) as f:
+ CHANGES = f.read()
+
+ requires = ['pyramid', 'pyramid_debugtoolbar']
+
+ tests_require = [
+ 'WebTest >= 1.3.1', # py3 compat
+ 'pytest', # includes virtualenv
+ 'pytest-cov',
+ ]
+
+ setup(name='MyProject',
+ version='0.0',
+ description='My project',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ "Programming Language :: Python",
+ "Framework :: Pyramid",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=requires,
+ extras_require={
+ 'testing': tests_require,
+ },
+ entry_points = """\
+ [paste.app_factory]
+ main = myproject:main
+ """,
+ )
We're going to change the ``setup.py`` file to add a ``[console_scripts]``
section within the ``entry_points`` string. Within this section, you should
@@ -987,8 +987,8 @@ specify a ``scriptname = dotted.path.to:yourfunction`` line. For example:
.. code-block:: ini
- [console_scripts]
- show_settings = myproject.scripts:settings_show
+ [console_scripts]
+ show_settings = myproject.scripts:settings_show
The ``show_settings`` name will be the name of the script that is installed
into ``bin``. The colon (``:``) between ``myproject.scripts`` and
@@ -1000,55 +1000,55 @@ script from their command line.
The result will be something like:
.. code-block:: python
- :linenos:
- :emphasize-lines: 43-44
-
- import os
-
- from setuptools import setup, find_packages
-
- here = os.path.abspath(os.path.dirname(__file__))
- with open(os.path.join(here, 'README.txt')) as f:
- README = f.read()
- with open(os.path.join(here, 'CHANGES.txt')) as f:
- CHANGES = f.read()
-
- requires = ['pyramid', 'pyramid_debugtoolbar']
-
- tests_require = [
- 'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
- 'pytest-cov',
- ]
-
- setup(name='MyProject',
- version='0.0',
- description='My project',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pyramid pylons',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=requires,
- extras_require={
- 'testing': tests_require,
- },
- entry_points = """\
- [paste.app_factory]
- main = myproject:main
- [console_scripts]
- show_settings = myproject.scripts:settings_show
- """,
- )
+ :linenos:
+ :emphasize-lines: 43-44
+
+ import os
+
+ from setuptools import setup, find_packages
+
+ here = os.path.abspath(os.path.dirname(__file__))
+ with open(os.path.join(here, 'README.txt')) as f:
+ README = f.read()
+ with open(os.path.join(here, 'CHANGES.txt')) as f:
+ CHANGES = f.read()
+
+ requires = ['pyramid', 'pyramid_debugtoolbar']
+
+ tests_require = [
+ 'WebTest >= 1.3.1', # py3 compat
+ 'pytest', # includes virtualenv
+ 'pytest-cov',
+ ]
+
+ setup(name='MyProject',
+ version='0.0',
+ description='My project',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ "Programming Language :: Python",
+ "Framework :: Pyramid",
+ "Topic :: Internet :: WWW/HTTP",
+ "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=requires,
+ extras_require={
+ 'testing': tests_require,
+ },
+ entry_points = """\
+ [paste.app_factory]
+ main = myproject:main
+ [console_scripts]
+ show_settings = myproject.scripts:settings_show
+ """,
+ )
Once you've done this, invoking ``$VENV/bin/pip install -e .`` will install a
file named ``show_settings`` into the ``$somevenv/bin`` directory with a
@@ -1062,17 +1062,17 @@ start with either ``foo`` or ``bar``:
.. code-block:: bash
- $ $VENV/bin/show_settings development.ini --omit=pyramid --omit=debugtoolbar
- debug_routematch False
- debug_templates True
- reload_templates True
- mako.directories []
- debug_notfound False
- default_locale_name en
- reload_resources False
- debug_authorization False
- reload_assets False
- prevent_http_cache False
+ $VENV/bin/show_settings development.ini --omit=pyramid --omit=debugtoolbar
+ debug_routematch False
+ debug_templates True
+ reload_templates True
+ mako.directories []
+ debug_notfound False
+ default_locale_name en
+ reload_resources False
+ debug_authorization False
+ reload_assets False
+ prevent_http_cache False
Pyramid's ``pserve``, ``pcreate``, ``pshell``, ``prequest``, ``ptweens``, and
other ``p*`` scripts are implemented as console scripts. When you invoke one
diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst
index bbf01240e..5477c4ff6 100644
--- a/docs/narr/configuration.rst
+++ b/docs/narr/configuration.rst
@@ -37,21 +37,21 @@ one after the next. Here's one of the simplest :app:`Pyramid` applications,
configured imperatively:
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
- if __name__ == '__main__':
- 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()
+ if __name__ == '__main__':
+ 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()
We won't talk much about what this application does yet. Just note that the
configuration statements take place underneath the ``if __name__ ==
@@ -80,14 +80,14 @@ by the configuration. To avoid this, :app:`Pyramid` allows you to insert
to by the declaration itself. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config(name='hello', request_method='GET')
- def hello(request):
- return Response('Hello')
+ @view_config(name='hello', request_method='GET')
+ def hello(request):
+ return Response('Hello')
The mere existence of configuration decoration doesn't cause any configuration
registration to be performed. Before it has any effect on the configuration of
@@ -104,23 +104,23 @@ invoked: scanning implies searching for configuration declarations in a package
and its subpackages. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.response import Response
- from pyramid.view import view_config
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config()
- def hello(request):
- return Response('Hello')
+ @view_config()
+ def hello(request):
+ return Response('Hello')
- if __name__ == '__main__':
- with Configurator() as config:
- config.scan()
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ if __name__ == '__main__':
+ with Configurator() as config:
+ config.scan()
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
The scanning machinery imports each module and subpackage in a package or
module recursively, looking for special attributes attached to objects defined
@@ -143,7 +143,7 @@ In the example above, the scanner translates the arguments to
.. code-block:: python
- config.add_view(hello)
+ config.add_view(hello)
Summary
-------
diff --git a/docs/narr/environment.rst b/docs/narr/environment.rst
index 743266d2c..db853780e 100644
--- a/docs/narr/environment.rst
+++ b/docs/narr/environment.rst
@@ -258,23 +258,23 @@ file in your application:
.. code-block:: ini
- [app:main]
- pyramid.includes = pyramid_debugtoolbar
- pyramid_tm
+ [app:main]
+ pyramid.includes = pyramid_debugtoolbar
+ pyramid_tm
Is equivalent to using the following statements in your configuration code:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def main(global_config, **settings):
- config = Configurator(settings=settings)
- # ...
- config.include('pyramid_debugtoolbar')
- config.include('pyramid_tm')
- # ...
+ def main(global_config, **settings):
+ config = Configurator(settings=settings)
+ # ...
+ config.include('pyramid_debugtoolbar')
+ config.include('pyramid_tm')
+ # ...
It is fine to use both or either form.
@@ -285,26 +285,26 @@ Using the following ``pyramid.includes`` setting in your plain-Python Pyramid
application:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- if __name__ == '__main__':
- settings = {'pyramid.includes':'pyramid_debugtoolbar pyramid_tm'}
- config = Configurator(settings=settings)
+ if __name__ == '__main__':
+ settings = {'pyramid.includes':'pyramid_debugtoolbar pyramid_tm'}
+ config = Configurator(settings=settings)
Is equivalent to using the following statements in your configuration code:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- if __name__ == '__main__':
- settings = {}
- config = Configurator(settings=settings)
- config.include('pyramid_debugtoolbar')
- config.include('pyramid_tm')
+ if __name__ == '__main__':
+ settings = {}
+ config = Configurator(settings=settings)
+ config.include('pyramid_debugtoolbar')
+ config.include('pyramid_tm')
It is fine to use both or either form.
@@ -367,25 +367,25 @@ in your application:
.. code-block:: ini
- [app:main]
- pyramid.tweens = pyramid_debugtoolbar.toolbar.tween_factory
- pyramid.tweens.excview_tween_factory
- pyramid_tm.tm_tween_factory
+ [app:main]
+ pyramid.tweens = pyramid_debugtoolbar.toolbar.tween_factory
+ pyramid.tweens.excview_tween_factory
+ pyramid_tm.tm_tween_factory
Is equivalent to using the following statements in your configuration code:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def main(global_config, **settings):
- settings['pyramid.tweens'] = [
- 'pyramid_debugtoolbar.toolbar.tween_factory',
- 'pyramid.tweebs.excview_tween_factory',
- 'pyramid_tm.tm_tween_factory',
- ]
- config = Configurator(settings=settings)
+ def main(global_config, **settings):
+ settings['pyramid.tweens'] = [
+ 'pyramid_debugtoolbar.toolbar.tween_factory',
+ 'pyramid.tweebs.excview_tween_factory',
+ 'pyramid_tm.tm_tween_factory',
+ ]
+ config = Configurator(settings=settings)
It is fine to use both or either form.
@@ -399,12 +399,12 @@ settings documented in the above "Config File Setting Name" column would go in
the ``[app:main]`` section. Here's an example of such a section:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyProject
- pyramid.reload_templates = true
- pyramid.debug_authorization = true
+ [app:main]
+ use = egg:MyProject
+ pyramid.reload_templates = true
+ pyramid.debug_authorization = true
You can also use environment variables to accomplish the same purpose for
settings documented as such. For example, you might start your :app:`Pyramid`
@@ -412,8 +412,8 @@ application using the following command line:
.. code-block:: text
- $ PYRAMID_DEBUG_AUTHORIZATION=1 PYRAMID_RELOAD_TEMPLATES=1 \
- $VENV/bin/pserve MyProject.ini
+ PYRAMID_DEBUG_AUTHORIZATION=1 PYRAMID_RELOAD_TEMPLATES=1 \
+ $VENV/bin/pserve MyProject.ini
If you started your application this way, your :app:`Pyramid` application would
behave in the same manner as if you had placed the respective settings in the
@@ -494,9 +494,9 @@ Here's how:
.. code-block:: ini
- [app:main]
- # .. other settings
- debug_frobnosticator = True
+ [app:main]
+ # .. other settings
+ debug_frobnosticator = True
- In the ``main()`` function that represents the place that your Pyramid WSGI
application is created, anticipate that you'll be getting this key/value pair
@@ -508,13 +508,13 @@ Here's how:
.. code-block:: python
- def main(global_config, **settings):
- # ...
- from pyramid.settings import asbool
- debug_frobnosticator = asbool(settings.get(
- 'debug_frobnosticator', 'false'))
- settings['debug_frobnosticator'] = debug_frobnosticator
- config = Configurator(settings=settings)
+ def main(global_config, **settings):
+ # ...
+ from pyramid.settings import asbool
+ debug_frobnosticator = asbool(settings.get(
+ 'debug_frobnosticator', 'false'))
+ settings['debug_frobnosticator'] = debug_frobnosticator
+ config = Configurator(settings=settings)
.. note::
It's especially important that you mutate the ``settings`` dictionary with
@@ -529,9 +529,9 @@ Here's how:
.. code-block:: python
- def includeme(config):
- settings = config.registry.settings
- debug_frobnosticator = settings['debug_frobnosticator']
+ def includeme(config):
+ settings = config.registry.settings
+ debug_frobnosticator = settings['debug_frobnosticator']
- In the runtime code from where you need to access the new settings value,
find the value in the ``registry.settings`` dictionary and use it. In
@@ -540,8 +540,8 @@ Here's how:
.. code-block:: python
- settings = request.registry.settings
- debug_frobnosticator = settings['debug_frobnosticator']
+ settings = request.registry.settings
+ debug_frobnosticator = settings['debug_frobnosticator']
If you wish to use the value in code that does not have access to the request
and you wish to use the value, you'll need to use the
@@ -550,6 +550,6 @@ Here's how:
.. code-block:: python
- registry = pyramid.threadlocal.get_current_registry()
- settings = registry.settings
- debug_frobnosticator = settings['debug_frobnosticator']
+ registry = pyramid.threadlocal.get_current_registry()
+ settings = registry.settings
+ debug_frobnosticator = settings['debug_frobnosticator']
diff --git a/docs/narr/events.rst b/docs/narr/events.rst
index c10d4cc47..e4b974099 100644
--- a/docs/narr/events.rst
+++ b/docs/narr/events.rst
@@ -23,10 +23,10 @@ only become useful when you register a *subscriber*. A subscriber is a
function that accepts a single argument named `event`:
.. code-block:: python
- :linenos:
+ :linenos:
- def mysubscriber(event):
- print(event)
+ def mysubscriber(event):
+ print(event)
The above is a subscriber that simply prints the event to the console when it's
called.
@@ -44,16 +44,16 @@ You can imperatively configure a subscriber function to be called for some
event type via the :meth:`~pyramid.config.Configurator.add_subscriber` method:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.events import NewRequest
+ from pyramid.events import NewRequest
- from subscribers import mysubscriber
+ from subscribers import mysubscriber
- # "config" below is assumed to be an instance of a
- # pyramid.config.Configurator object
+ # "config" below is assumed to be an instance of a
+ # pyramid.config.Configurator object
- config.add_subscriber(mysubscriber, NewRequest)
+ config.add_subscriber(mysubscriber, NewRequest)
The first argument to :meth:`~pyramid.config.Configurator.add_subscriber` is
the subscriber function (or a :term:`dotted Python name` which refers to a
@@ -70,14 +70,14 @@ You can configure a subscriber function to be called for some event type via
the :func:`pyramid.events.subscriber` function.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.events import NewRequest
- from pyramid.events import subscriber
+ from pyramid.events import NewRequest
+ from pyramid.events import subscriber
- @subscriber(NewRequest)
- def mysubscriber(event):
- event.request.foo = 1
+ @subscriber(NewRequest)
+ def mysubscriber(event):
+ event.request.foo = 1
When the :func:`~pyramid.events.subscriber` decorator is used, a :term:`scan`
must be performed against the package containing the decorated function for the
@@ -109,26 +109,26 @@ If you create event listener functions in a ``subscribers.py`` file in your
application like so:
.. code-block:: python
- :linenos:
+ :linenos:
- def handle_new_request(event):
- print('request', event.request)
+ def handle_new_request(event):
+ print('request', event.request)
- def handle_new_response(event):
- print('response', event.response)
+ def handle_new_response(event):
+ print('response', event.response)
You may configure these functions to be called at the appropriate times by
adding the following code to your application's configuration startup:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_subscriber('myproject.subscribers.handle_new_request',
- 'pyramid.events.NewRequest')
- config.add_subscriber('myproject.subscribers.handle_new_response',
- 'pyramid.events.NewResponse')
+ config.add_subscriber('myproject.subscribers.handle_new_request',
+ 'pyramid.events.NewRequest')
+ config.add_subscriber('myproject.subscribers.handle_new_response',
+ 'pyramid.events.NewResponse')
Either mechanism causes the functions in ``subscribers.py`` to be registered as
event subscribers. Under this configuration, when the application is run, each
diff --git a/docs/narr/extconfig.rst b/docs/narr/extconfig.rst
index 4009ec1dc..61bd7a05f 100644
--- a/docs/narr/extconfig.rst
+++ b/docs/narr/extconfig.rst
@@ -33,30 +33,30 @@ argument and accepts other arbitrary positional and keyword arguments. For
example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.events import NewRequest
- from pyramid.config import Configurator
+ from pyramid.events import NewRequest
+ from pyramid.config import Configurator
- def add_newrequest_subscriber(config, subscriber):
- config.add_subscriber(subscriber, NewRequest)
+ def add_newrequest_subscriber(config, subscriber):
+ config.add_subscriber(subscriber, NewRequest)
- if __name__ == '__main__':
- config = Configurator()
- config.add_directive('add_newrequest_subscriber',
- add_newrequest_subscriber)
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_newrequest_subscriber',
+ add_newrequest_subscriber)
Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can
then call the added directive by its given name as if it were a built-in method
of the Configurator:
.. code-block:: python
- :linenos:
+ :linenos:
- def mysubscriber(event):
- print(event.request)
+ def mysubscriber(event):
+ print(event.request)
- config.add_newrequest_subscriber(mysubscriber)
+ config.add_newrequest_subscriber(mysubscriber)
A call to :meth:`~pyramid.config.Configurator.add_directive` is often "hidden"
within an ``includeme`` function within a "frameworky" package meant to be
@@ -65,25 +65,25 @@ included as per :ref:`including_configuration` via
code in a package named ``pyramid_subscriberhelpers``:
.. code-block:: python
- :linenos:
+ :linenos:
- def includeme(config):
- config.add_directive('add_newrequest_subscriber',
- add_newrequest_subscriber)
+ def includeme(config):
+ config.add_directive('add_newrequest_subscriber',
+ add_newrequest_subscriber)
The user of the add-on package ``pyramid_subscriberhelpers`` would then be able
to install it and subsequently do:
.. code-block:: python
- :linenos:
+ :linenos:
- def mysubscriber(event):
- print(event.request)
+ def mysubscriber(event):
+ print(event.request)
- from pyramid.config import Configurator
- config = Configurator()
- config.include('pyramid_subscriberhelpers')
- config.add_newrequest_subscriber(mysubscriber)
+ from pyramid.config import Configurator
+ config = Configurator()
+ config.include('pyramid_subscriberhelpers')
+ config.add_newrequest_subscriber(mysubscriber)
Using ``config.action`` in a Directive
--------------------------------------
@@ -100,16 +100,16 @@ function, and possibly other metadata used by Pyramid's action system.
Here's an example directive which uses the "action" method:
.. code-block:: python
- :linenos:
+ :linenos:
- def add_jammyjam(config, jammyjam):
- def register():
- config.registry.jammyjam = jammyjam
- config.action('jammyjam', register)
+ def add_jammyjam(config, jammyjam):
+ def register():
+ config.registry.jammyjam = jammyjam
+ config.action('jammyjam', register)
- if __name__ == '__main__':
- config = Configurator()
- config.add_directive('add_jammyjam', add_jammyjam)
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_jammyjam', add_jammyjam)
Fancy, but what does it do? The action method accepts a number of arguments.
In the above directive named ``add_jammyjam``, we call
@@ -135,8 +135,8 @@ directive did this:
.. code-block:: python
- config.add_jammyjam('first')
- config.add_jammyjam('second')
+ config.add_jammyjam('first')
+ config.add_jammyjam('second')
When the action list was committed resulting from the set of calls above, our
user's application would not start, because the discriminators of the actions
@@ -160,7 +160,7 @@ that no configuration conflicts are generated.
.. code-block:: python
- config.add_jammyjam('first')
+ config.add_jammyjam('first')
What happens now? When the ``add_jammyjam`` method is called, an action is
appended to the pending actions list. When the pending configuration actions
@@ -183,14 +183,14 @@ to the ``callable`` function when it is called back. For example, our
directive might use them like so:
.. code-block:: python
- :linenos:
+ :linenos:
- def add_jammyjam(config, jammyjam):
- def register(*arg, **kw):
- config.registry.jammyjam_args = arg
- config.registry.jammyjam_kw = kw
- config.registry.jammyjam = jammyjam
- config.action('jammyjam', register, args=('one',), kw={'two':'two'})
+ def add_jammyjam(config, jammyjam):
+ def register(*arg, **kw):
+ config.registry.jammyjam_args = arg
+ config.registry.jammyjam_kw = kw
+ config.registry.jammyjam = jammyjam
+ config.action('jammyjam', register, args=('one',), kw={'two':'two'})
In the above example, when this directive is used to generate an action, and
that action is committed, ``config.registry.jammyjam_args`` will be set to
@@ -291,18 +291,18 @@ For example, let's make an addon that invokes ``add_route`` and ``add_view``,
but we want it to conflict with any other call to our addon:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import PHASE0_CONFIG
+ from pyramid.config import PHASE0_CONFIG
- def includeme(config):
- config.add_directive('add_auto_route', add_auto_route)
+ def includeme(config):
+ config.add_directive('add_auto_route', add_auto_route)
- def add_auto_route(config, name, view):
- def register():
- config.add_view(route_name=name, view=view)
- config.add_route(name, '/' + name)
- config.action(('auto route', name), register, order=PHASE0_CONFIG)
+ def add_auto_route(config, name, view):
+ def register():
+ config.add_view(route_name=name, view=view)
+ config.add_route(name, '/' + name)
+ config.action(('auto route', name), register, order=PHASE0_CONFIG)
Now someone else can use your addon and be informed if there is a conflict
between this route and another, or two calls to ``add_auto_route``. Notice how
@@ -313,17 +313,17 @@ executed, and the configurator cannot go back in time to add more views during
that commit-cycle.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def main(global_config, **settings):
- config = Configurator()
- config.include('auto_route_addon')
- config.add_auto_route('foo', my_view)
+ def main(global_config, **settings):
+ config = Configurator()
+ config.include('auto_route_addon')
+ config.add_auto_route('foo', my_view)
- def my_view(request):
- return request.response
+ def my_view(request):
+ return request.response
.. _introspection:
@@ -354,21 +354,21 @@ is passed to the :meth:`~pyramid.config.Configurator.action` method. Here's an
example of a directive which uses introspectables:
.. code-block:: python
- :linenos:
-
- def add_jammyjam(config, value):
- def register():
- config.registry.jammyjam = value
- intr = config.introspectable(category_name='jammyjams',
- discriminator='jammyjam',
- title='a jammyjam',
- type_name=None)
- intr['value'] = value
- config.action('jammyjam', register, introspectables=(intr,))
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_directive('add_jammyjam', add_jammyjam)
+ :linenos:
+
+ def add_jammyjam(config, value):
+ def register():
+ config.registry.jammyjam = value
+ intr = config.introspectable(category_name='jammyjams',
+ discriminator='jammyjam',
+ title='a jammyjam',
+ type_name=None)
+ intr['value'] = value
+ config.action('jammyjam', register, introspectables=(intr,))
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_jammyjam', add_jammyjam)
If you notice, the above directive uses the ``introspectable`` attribute of a
Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create an
@@ -413,27 +413,27 @@ Introspectable Relationships
Two introspectables may have relationships between each other.
.. code-block:: python
- :linenos:
-
- def add_jammyjam(config, value, template):
- def register():
- config.registry.jammyjam = (value, template)
- intr = config.introspectable(category_name='jammyjams',
- discriminator='jammyjam',
- title='a jammyjam',
- type_name=None)
- intr['value'] = value
- tmpl_intr = config.introspectable(category_name='jammyjam templates',
- discriminator=template,
- title=template,
- type_name=None)
- tmpl_intr['value'] = template
- intr.relate('jammyjam templates', template)
- config.action('jammyjam', register, introspectables=(intr, tmpl_intr))
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_directive('add_jammyjam', add_jammyjam)
+ :linenos:
+
+ def add_jammyjam(config, value, template):
+ def register():
+ config.registry.jammyjam = (value, template)
+ intr = config.introspectable(category_name='jammyjams',
+ discriminator='jammyjam',
+ title='a jammyjam',
+ type_name=None)
+ intr['value'] = value
+ tmpl_intr = config.introspectable(category_name='jammyjam templates',
+ discriminator=template,
+ title=template,
+ type_name=None)
+ tmpl_intr['value'] = template
+ intr.relate('jammyjam templates', template)
+ config.action('jammyjam', register, introspectables=(intr, tmpl_intr))
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_jammyjam', add_jammyjam)
In the above example, the ``add_jammyjam`` directive registers two
introspectables: the first is related to the ``value`` passed to the directive,
diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst
index bee30ec1a..1a6804792 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -75,30 +75,30 @@ inlined as calls to methods of a :term:`Configurator` within the ``main``
function in your application's ``__init__.py``. For example, rather than:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- if __name__ == '__main__':
- config = Configurator()
- config.add_view('myapp.views.view1', name='view1')
- config.add_view('myapp.views.view2', name='view2')
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_view('myapp.views.view1', name='view1')
+ config.add_view('myapp.views.view2', name='view2')
You should move the calls to ``add_view`` outside of the (non-reusable) ``if
__name__ == '__main__'`` block, and into a reusable function:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- if __name__ == '__main__':
- config = Configurator()
- config.include(add_views)
+ if __name__ == '__main__':
+ config = Configurator()
+ config.include(add_views)
- def add_views(config):
- config.add_view('myapp.views.view1', name='view1')
- config.add_view('myapp.views.view2', name='view2')
+ def add_views(config):
+ config.add_view('myapp.views.view1', name='view1')
+ config.add_view('myapp.views.view2', name='view2')
Doing this allows an integrator to maximally reuse the configuration statements
that relate to your application by allowing them to selectively include or
@@ -145,11 +145,11 @@ against the application's package, then add additional configuration that
registers more views or routes.
.. code-block:: python
- :linenos:
+ :linenos:
- if __name__ == '__main__':
- config.scan('someotherpackage')
- config.add_view('mypackage.views.myview', name='myview')
+ if __name__ == '__main__':
+ config.scan('someotherpackage')
+ config.add_view('mypackage.views.myview', name='myview')
If you want to *override* configuration in the application, you *may* need to
run :meth:`pyramid.config.Configurator.commit` after performing the scan of the
@@ -157,12 +157,12 @@ original package, then add additional configuration that registers more views
or routes which perform overrides.
.. code-block:: python
- :linenos:
+ :linenos:
- if __name__ == '__main__':
- config.scan('someotherpackage')
- config.commit()
- config.add_view('mypackage.views.myview', name='myview')
+ if __name__ == '__main__':
+ config.scan('someotherpackage')
+ config.commit()
+ config.add_view('mypackage.views.myview', name='myview')
Once this is done, you should be able to extend or override the application
like any other (see :ref:`extending_the_application`).
@@ -241,15 +241,15 @@ You can override the first view configuration statement made by
configuration function:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- from originalapp import configure_views
+ from pyramid.config import Configurator
+ from originalapp import configure_views
- if __name == '__main__':
- config = Configurator()
- config.include(configure_views)
- config.add_view('theoverrideapp.views.theview', name='theview')
+ if __name == '__main__':
+ config = Configurator()
+ config.include(configure_views)
+ config.add_view('theoverrideapp.views.theview', name='theview')
In this case, the ``theoriginalapp.views.theview`` view will never be executed.
Instead, a new view, ``theoverrideapp.views.theview`` will be executed when
diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst
index db55f2f9c..5eb067fe2 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -25,17 +25,17 @@ When this code is inserted into a Python script named ``helloworld.py`` and
executed by a Python interpreter which has the :app:`Pyramid` software
installed, an HTTP server is started on TCP port 8080.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/python helloworld.py
+ $VENV/bin/python helloworld.py
On Windows:
.. code-block:: doscon
- c:\> %VENV%\Scripts\python helloworld.py
+ %VENV%\Scripts\python helloworld.py
This command will not return and nothing will be printed to the console. When
port 8080 is visited by a browser on the URL ``/hello/world``, the server will
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index f9bb72986..9f405c336 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -23,14 +23,14 @@ Not Found View by using the
:meth:`pyramid.config.Configurator.add_notfound_view` method:
.. code-block:: python
- :linenos:
+ :linenos:
- def notfound(request):
- return Response('Not Found', status='404 Not Found')
+ def notfound(request):
+ return Response('Not Found', status='404 Not Found')
- def main(globals, **settings):
- config = Configurator()
- config.add_notfound_view(notfound)
+ def main(globals, **settings):
+ config = Configurator()
+ config.add_notfound_view(notfound)
The :term:`Not Found View` callable is a view callable like any other.
@@ -39,17 +39,17 @@ and a :term:`scan`, you can replace the Not Found View by using the
:class:`pyramid.view.notfound_view_config` decorator:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import notfound_view_config
+ from pyramid.view import notfound_view_config
- @notfound_view_config()
- def notfound(request):
- return Response('Not Found', status='404 Not Found')
+ @notfound_view_config()
+ def notfound(request):
+ return Response('Not Found', status='404 Not Found')
- def main(globals, **settings):
- config = Configurator()
- config.scan()
+ def main(globals, **settings):
+ config = Configurator()
+ config.scan()
This does exactly what the imperative example above showed.
@@ -61,21 +61,21 @@ Your application can define *multiple* Not Found Views if necessary. Both
Views can carry predicates limiting their applicability. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import notfound_view_config
+ from pyramid.view import notfound_view_config
- @notfound_view_config(request_method='GET')
- def notfound_get(request):
- return Response('Not Found during GET', status='404 Not Found')
+ @notfound_view_config(request_method='GET')
+ def notfound_get(request):
+ return Response('Not Found during GET', status='404 Not Found')
- @notfound_view_config(request_method='POST')
- def notfound_post(request):
- return Response('Not Found during POST', status='404 Not Found')
+ @notfound_view_config(request_method='POST')
+ def notfound_post(request):
+ return Response('Not Found during POST', status='404 Not Found')
- def main(globals, **settings):
- config = Configurator()
- config.scan()
+ def main(globals, **settings):
+ config = Configurator()
+ config.scan()
The ``notfound_get`` view will be called when a view could not be found and the
request method was ``GET``. The ``notfound_post`` view will be called when a
@@ -97,12 +97,12 @@ Here's some sample code that implements a minimal :term:`Not Found View`
callable:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPNotFound
+ from pyramid.httpexceptions import HTTPNotFound
- def notfound(request):
- return HTTPNotFound()
+ def notfound(request):
+ return HTTPNotFound()
.. note::
@@ -153,31 +153,31 @@ For example, you can add a forbidden view by using the
forbidden view:
.. code-block:: python
- :linenos:
+ :linenos:
- def forbidden(request):
- return Response('forbidden')
+ def forbidden(request):
+ return Response('forbidden')
- def main(globals, **settings):
- config = Configurator()
- config.add_forbidden_view(forbidden)
+ def main(globals, **settings):
+ config = Configurator()
+ config.add_forbidden_view(forbidden)
If instead you prefer to use decorators and a :term:`scan`, you can use the
:class:`pyramid.view.forbidden_view_config` decorator to mark a view callable
as a forbidden view:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import forbidden_view_config
+ from pyramid.view import forbidden_view_config
- @forbidden_view_config()
- def forbidden(request):
- return Response('forbidden')
+ @forbidden_view_config()
+ def forbidden(request):
+ return Response('forbidden')
- def main(globals, **settings):
- config = Configurator()
- config.scan()
+ def main(globals, **settings):
+ config = Configurator()
+ config.scan()
Like any other view, the forbidden view must accept at least a ``request``
parameter, or both ``context`` and ``request``. If a forbidden view callable
@@ -189,13 +189,13 @@ you normally would expect) is available as ``request.context``. The
Here's some sample code that implements a minimal forbidden view:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- def forbidden_view(request):
- return Response('forbidden')
+ def forbidden_view(request):
+ return Response('forbidden')
.. note::
@@ -235,30 +235,30 @@ constructor of the :term:`configurator`. This argument can be either a
callable or a :term:`dotted Python name` representing a callable.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.request import Request
+ from pyramid.request import Request
- class MyRequest(Request):
- pass
+ class MyRequest(Request):
+ pass
- config = Configurator(request_factory=MyRequest)
+ config = Configurator(request_factory=MyRequest)
If you're doing imperative configuration, and you'd rather do it after you've
already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_request_factory` method:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- from pyramid.request import Request
+ from pyramid.config import Configurator
+ from pyramid.request import Request
- class MyRequest(Request):
- pass
+ class MyRequest(Request):
+ pass
- config = Configurator()
- config.set_request_factory(MyRequest)
+ config = Configurator()
+ config.set_request_factory(MyRequest)
.. index::
single: request method
@@ -286,20 +286,20 @@ actually execute the function until accessed.
factory` that have the same name.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def total(request, *args):
- return sum(args)
+ def total(request, *args):
+ return sum(args)
- def prop(request):
- print("getting the property")
- return "the property"
+ def prop(request):
+ print("getting the property")
+ return "the property"
- config = Configurator()
- config.add_request_method(total)
- config.add_request_method(prop, reify=True)
+ config = Configurator()
+ config.add_request_method(total)
+ config.add_request_method(prop, reify=True)
In the above example, ``total`` is added as a method. However, ``prop`` is
added as a property and its result is cached per-request by setting
@@ -345,27 +345,27 @@ To not cache the result of ``request.prop``, set ``property=True`` instead of
Here is an example of passing a class to ``Configurator.add_request_method``:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- from pyramid.decorator import reify
+ from pyramid.config import Configurator
+ from pyramid.decorator import reify
- class ExtraStuff(object):
+ class ExtraStuff(object):
- def __init__(self, request):
- self.request = request
+ def __init__(self, request):
+ self.request = request
- def total(self, *args):
- return sum(args)
+ def total(self, *args):
+ return sum(args)
- # use @property if you don't want to cache the result
- @reify
- def prop(self):
- print("getting the property")
- return "the property"
+ # use @property if you don't want to cache the result
+ @reify
+ def prop(self):
+ print("getting the property")
+ return "the property"
- config = Configurator()
- config.add_request_method(ExtraStuff, 'extra', reify=True)
+ config = Configurator()
+ config.add_request_method(ExtraStuff, 'extra', reify=True)
We attach and cache an object named ``extra`` to the ``request`` object.
@@ -430,30 +430,30 @@ The factory takes a single positional argument, which is a :term:`Request`
object. The argument may be ``None``.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- class MyResponse(Response):
- pass
+ class MyResponse(Response):
+ pass
- config = Configurator(response_factory=lambda r: MyResponse())
+ config = Configurator(response_factory=lambda r: MyResponse())
If you're doing imperative configuration and you'd rather do it after you've
already constructed a :term:`configurator`, it can also be registered via the
:meth:`pyramid.config.Configurator.set_response_factory` method:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- from pyramid.response import Response
+ from pyramid.config import Configurator
+ from pyramid.response import Response
- class MyResponse(Response):
- pass
+ class MyResponse(Response):
+ pass
- config = Configurator()
- config.set_response_factory(lambda r: MyResponse())
+ config = Configurator()
+ config.set_response_factory(lambda r: MyResponse())
.. index::
single: before render event
@@ -497,27 +497,27 @@ Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from your
view callable, like so:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='some_renderer')
- def myview(request):
- return {'mykey': 'somevalue', 'mykey2': 'somevalue2'}
+ @view_config(renderer='some_renderer')
+ def myview(request):
+ return {'mykey': 'somevalue', 'mykey2': 'somevalue2'}
:attr:`rendering_val` can be used to access these values from the
:class:`~pyramid.events.BeforeRender` object:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.events import subscriber
- from pyramid.events import BeforeRender
+ from pyramid.events import subscriber
+ from pyramid.events import BeforeRender
- @subscriber(BeforeRender)
- def read_return(event):
- # {'mykey': 'somevalue'} is returned from the view
- print(event.rendering_val['mykey'])
+ @subscriber(BeforeRender)
+ def read_return(event):
+ # {'mykey': 'somevalue'} is returned from the view
+ print(event.rendering_val['mykey'])
See the API documentation for the :class:`~pyramid.events.BeforeRender` event
interface at :class:`pyramid.interfaces.IBeforeRender`.
@@ -542,13 +542,13 @@ A response callback is a callable which accepts two positional parameters:
``request`` and ``response``. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- def cache_callback(request, response):
- """Set the cache_control max_age for the response"""
- if request.exception is not None:
- response.cache_control.max_age = 360
- request.add_response_callback(cache_callback)
+ def cache_callback(request, response):
+ """Set the cache_control max_age for the response"""
+ if request.exception is not None:
+ response.cache_control.max_age = 360
+ request.add_response_callback(cache_callback)
No response callback is called if an unhandled exception happens in application
code, or if the response object returned by a :term:`view callable` is invalid.
@@ -588,16 +588,16 @@ A finished callback is a callable which accepts a single positional parameter:
``request``. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- import logging
+ import logging
- log = logging.getLogger(__name__)
+ log = logging.getLogger(__name__)
- def log_callback(request):
- """Log information at the end of request"""
- log.debug('Request is finished.')
- request.add_finished_callback(log_callback)
+ def log_callback(request):
+ """Log information at the end of request"""
+ log.debug('Request is finished.')
+ request.add_finished_callback(log_callback)
Finished callbacks are called in the order they're added
(first-to-most-recently-added). Finished callbacks (unlike a :term:`response
@@ -636,46 +636,46 @@ algorithm can be swapped out selectively for a different traversal pattern via
configuration.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- from myapp.traversal import Traverser
- config = Configurator()
- config.add_traverser(Traverser)
+ from pyramid.config import Configurator
+ from myapp.traversal import Traverser
+ config = Configurator()
+ config.add_traverser(Traverser)
In the example above, ``myapp.traversal.Traverser`` is assumed to be a class
that implements the following interface:
.. code-block:: python
- :linenos:
+ :linenos:
+
+ class Traverser(object):
+ def __init__(self, root):
+ """ Accept the root object returned from the root factory """
- class Traverser(object):
- def __init__(self, root):
- """ Accept the root object returned from the root factory """
-
- def __call__(self, request):
- """ Return a dictionary with (at least) the keys ``root``,
- ``context``, ``view_name``, ``subpath``, ``traversed``,
- ``virtual_root``, and ``virtual_root_path``. These values are
- typically the result of a resource tree traversal. ``root``
- is the physical root object, ``context`` will be a resource
- object, ``view_name`` will be the view name used (a Unicode
- name), ``subpath`` will be a sequence of Unicode names that
- followed the view name but were not traversed, ``traversed``
- will be a sequence of Unicode names that were traversed
- (including the virtual root path, if any) ``virtual_root``
- will be a resource object representing the virtual root (or the
- physical root if traversal was not performed), and
- ``virtual_root_path`` will be a sequence representing the
- virtual root path (a sequence of Unicode names) or None if
- traversal was not performed.
-
- Extra keys for special purpose functionality can be added as
- necessary.
-
- All values returned in the dictionary will be made available
- as attributes of the ``request`` object.
- """
+ def __call__(self, request):
+ """ Return a dictionary with (at least) the keys ``root``,
+ ``context``, ``view_name``, ``subpath``, ``traversed``,
+ ``virtual_root``, and ``virtual_root_path``. These values are
+ typically the result of a resource tree traversal. ``root``
+ is the physical root object, ``context`` will be a resource
+ object, ``view_name`` will be the view name used (a Unicode
+ name), ``subpath`` will be a sequence of Unicode names that
+ followed the view name but were not traversed, ``traversed``
+ will be a sequence of Unicode names that were traversed
+ (including the virtual root path, if any) ``virtual_root``
+ will be a resource object representing the virtual root (or the
+ physical root if traversal was not performed), and
+ ``virtual_root_path`` will be a sequence representing the
+ virtual root path (a sequence of Unicode names) or None if
+ traversal was not performed.
+
+ Extra keys for special purpose functionality can be added as
+ necessary.
+
+ All values returned in the dictionary will be made available
+ as attributes of the ``request`` object.
+ """
More than one traversal algorithm can be active at the same time. For
instance, if your :term:`root factory` returns more than one type of object
@@ -685,13 +685,13 @@ object that implemented that class or interface, a custom traverser would be
used. Otherwise the default traverser would be used. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from myapp.traversal import Traverser
- from myapp.resources import MyRoot
- from pyramid.config import Configurator
- config = Configurator()
- config.add_traverser(Traverser, MyRoot)
+ from myapp.traversal import Traverser
+ from myapp.resources import MyRoot
+ from pyramid.config import Configurator
+ config = Configurator()
+ config.add_traverser(Traverser, MyRoot)
If the above stanza was added to a Pyramid ``__init__.py`` file's ``main``
function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only when
@@ -721,12 +721,12 @@ type of resource by adding a call to
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from myapp.traversal import ResourceURLAdapter
- from myapp.resources import MyRoot
+ from myapp.traversal import ResourceURLAdapter
+ from myapp.resources import MyRoot
- config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)
+ config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)
In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be
used to provide services to :meth:`~pyramid.request.Request.resource_url` any
@@ -740,19 +740,19 @@ The API that must be implemented by a class that provides
:class:`~pyramid.interfaces.IResourceURL` is as follows:
.. code-block:: python
- :linenos:
-
- class MyResourceURL(object):
- """ An adapter which provides the virtual and physical paths of a
- resource
- """
- def __init__(self, resource, request):
- """ Accept the resource and request and set self.physical_path and
- self.virtual_path """
- self.virtual_path = some_function_of(resource, request)
- self.virtual_path_tuple = some_function_of(resource, request)
- self.physical_path = some_other_function_of(resource, request)
- self.physical_path_tuple = some_function_of(resource, request)
+ :linenos:
+
+ class MyResourceURL(object):
+ """ An adapter which provides the virtual and physical paths of a
+ resource
+ """
+ def __init__(self, resource, request):
+ """ Accept the resource and request and set self.physical_path and
+ self.virtual_path """
+ self.virtual_path = some_function_of(resource, request)
+ self.virtual_path_tuple = some_function_of(resource, request)
+ self.physical_path = some_other_function_of(resource, request)
+ self.physical_path_tuple = some_function_of(resource, request)
The default context URL generator is available for perusal as the class
:class:`pyramid.traversal.ResourceURL` in the `traversal module
@@ -798,38 +798,38 @@ objects (without requiring a :term:`renderer` to convert a string to a response
object), you can register an adapter which converts the string to a Response:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- def string_response_adapter(s):
- response = Response(s)
- return response
+ def string_response_adapter(s):
+ response = Response(s)
+ return response
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_response_adapter(string_response_adapter, str)
+ config.add_response_adapter(string_response_adapter, str)
Likewise, if you want to be able to return a simplified kind of response object
from view callables, you can use the IResponse hook to register an adapter to
the more complex IResponse interface:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- class SimpleResponse(object):
- def __init__(self, body):
- self.body = body
+ class SimpleResponse(object):
+ def __init__(self, body):
+ self.body = body
- def simple_response_adapter(simple_response):
- response = Response(simple_response.body)
- return response
+ def simple_response_adapter(simple_response):
+ response = Response(simple_response.body)
+ return response
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_response_adapter(simple_response_adapter, SimpleResponse)
+ config.add_response_adapter(simple_response_adapter, SimpleResponse)
If you want to implement your own Response object instead of using the
:class:`pyramid.response.Response` object in any capacity at all, you'll have
@@ -838,15 +838,15 @@ to make sure that the object implements every attribute and method outlined in
``zope.interface.implementer(IResponse)`` as a class decorator.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.interfaces import IResponse
- from zope.interface import implementer
+ from pyramid.interfaces import IResponse
+ from zope.interface import implementer
- @implementer(IResponse)
- class MyResponse(object):
- # ... an implementation of every method and attribute
- # documented in IResponse should follow ...
+ @implementer(IResponse)
+ class MyResponse(object):
+ # ... an implementation of every method and attribute
+ # documented in IResponse should follow ...
When an alternate response object implementation is returned by a view
callable, if that object asserts that it implements
@@ -864,21 +864,21 @@ Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, you
can use the :class:`pyramid.response.response_adapter` decorator:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.response import response_adapter
+ from pyramid.response import Response
+ from pyramid.response import response_adapter
- @response_adapter(str)
- def string_response_adapter(s):
- response = Response(s)
- return response
+ @response_adapter(str)
+ def string_response_adapter(s):
+ response = Response(s)
+ return response
The above example, when scanned, has the same effect as:
.. code-block:: python
- config.add_response_adapter(string_response_adapter, str)
+ config.add_response_adapter(string_response_adapter, str)
The :class:`~pyramid.response.response_adapter` decorator will have no effect
until activated by a :term:`scan`.
@@ -922,50 +922,50 @@ it. This somewhat emulates the Pylons style of calling action methods with
routing parameters pulled out of the route matching dict as keyword arguments.
.. code-block:: python
- :linenos:
+ :linenos:
- # framework
+ # framework
- class PylonsControllerViewMapper(object):
- def __init__(self, **kw):
- self.kw = kw
+ class PylonsControllerViewMapper(object):
+ def __init__(self, **kw):
+ self.kw = kw
- def __call__(self, view):
- attr = self.kw['attr']
- def wrapper(context, request):
- matchdict = request.matchdict.copy()
- matchdict.pop('action', None)
- inst = view(request)
- meth = getattr(inst, attr)
- return meth(**matchdict)
- return wrapper
+ def __call__(self, view):
+ attr = self.kw['attr']
+ def wrapper(context, request):
+ matchdict = request.matchdict.copy()
+ matchdict.pop('action', None)
+ inst = view(request)
+ meth = getattr(inst, attr)
+ return meth(**matchdict)
+ return wrapper
- class BaseController(object):
- __view_mapper__ = PylonsControllerViewMapper
+ class BaseController(object):
+ __view_mapper__ = PylonsControllerViewMapper
A user might make use of these framework components like so:
.. code-block:: python
- :linenos:
+ :linenos:
- # user application
+ # user application
- from pyramid.response import Response
- from pyramid.config import Configurator
- import pyramid_handlers
- from wsgiref.simple_server import make_server
+ from pyramid.response import Response
+ from pyramid.config import Configurator
+ import pyramid_handlers
+ from wsgiref.simple_server import make_server
- class MyController(BaseController):
- def index(self, id):
- return Response(id)
+ class MyController(BaseController):
+ def index(self, id):
+ return Response(id)
- if __name__ == '__main__':
- config = Configurator()
- config.include(pyramid_handlers)
- config.add_handler('one', '/{id}', MyController, action='index')
- config.add_handler('two', '/{action}/{id}', MyController)
- server.make_server('0.0.0.0', 8080, config.make_wsgi_app())
- server.serve_forever()
+ if __name__ == '__main__':
+ config = Configurator()
+ config.include(pyramid_handlers)
+ config.add_handler('one', '/{id}', MyController, action='index')
+ config.add_handler('two', '/{action}/{id}', MyController)
+ server.make_server('0.0.0.0', 8080, config.make_wsgi_app())
+ server.serve_forever()
The :meth:`pyramid.config.Configurator.set_view_mapper` method can be used to
set a *default* view mapper (overriding the superdefault view mapper used by
@@ -1002,62 +1002,62 @@ configuration had even begun.
However, using :term:`Venusian`, the decorator could be written as follows:
.. code-block:: python
- :linenos:
+ :linenos:
- import venusian
- from mypackage.interfaces import IMyUtility
+ import venusian
+ from mypackage.interfaces import IMyUtility
- class registerFunction(object):
+ class registerFunction(object):
- def __init__(self, path):
- self.path = path
+ def __init__(self, path):
+ self.path = path
- def register(self, scanner, name, wrapped):
- registry = scanner.config.registry
- registry.getUtility(IMyUtility).register(
- self.path, wrapped)
+ def register(self, scanner, name, wrapped):
+ registry = scanner.config.registry
+ registry.getUtility(IMyUtility).register(
+ self.path, wrapped)
- def __call__(self, wrapped):
- venusian.attach(wrapped, self.register)
- return wrapped
+ def __call__(self, wrapped):
+ venusian.attach(wrapped, self.register)
+ return wrapped
This decorator could then be used to register functions throughout your code:
.. code-block:: python
- :linenos:
+ :linenos:
- @registerFunction('/some/path')
- def my_function():
- do_stuff()
+ @registerFunction('/some/path')
+ def my_function():
+ do_stuff()
However, the utility would only be looked up when a :term:`scan` was performed,
enabling you to set up the utility in advance:
.. code-block:: python
- :linenos:
+ :linenos:
- from zope.interface import implementer
+ from zope.interface import implementer
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from mypackage.interfaces import IMyUtility
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from mypackage.interfaces import IMyUtility
- @implementer(IMyUtility)
- class UtilityImplementation:
+ @implementer(IMyUtility)
+ class UtilityImplementation:
- def __init__(self):
- self.registrations = {}
+ def __init__(self):
+ self.registrations = {}
- def register(self, path, callable_):
- self.registrations[path] = callable_
+ def register(self, path, callable_):
+ self.registrations[path] = callable_
- if __name__ == '__main__':
- config = Configurator()
- config.registry.registerUtility(UtilityImplementation())
- config.scan()
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ if __name__ == '__main__':
+ config = Configurator()
+ config.registry.registerUtility(UtilityImplementation())
+ config.scan()
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
For full details, please read the :ref:`Venusian documentation <venusian:venusian>`.
@@ -1246,7 +1246,9 @@ very last tween factory added) as its request handler function. For example:
config.add_tween('myapp.tween_factory1')
config.add_tween('myapp.tween_factory2')
-The above example will generate an implicit tween chain that looks like this::
+The above example will generate an implicit tween chain that looks like this.
+
+.. code-block:: text
INGRESS (implicit)
myapp.tween_factory2
@@ -1292,13 +1294,15 @@ factory represented by ``myapp.tween_factory`` directly "above" (in ``ptweens``
order) the main Pyramid request handler.
.. code-block:: python
- :linenos:
+ :linenos:
- import pyramid.tweens
+ import pyramid.tweens
- config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)
+ config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)
-The above example will generate an implicit tween chain that looks like this::
+The above example will generate an implicit tween chain that looks like this.
+
+.. code-block:: text
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
@@ -1310,15 +1314,15 @@ Likewise, calling the following call to
factory "above" the main handler but "below" a separately added tween factory:
.. code-block:: python
- :linenos:
+ :linenos:
- import pyramid.tweens
+ import pyramid.tweens
- config.add_tween('myapp.tween_factory1',
- over=pyramid.tweens.MAIN)
- config.add_tween('myapp.tween_factory2',
- over=pyramid.tweens.MAIN,
- under='myapp.tween_factory1')
+ config.add_tween('myapp.tween_factory1',
+ over=pyramid.tweens.MAIN)
+ config.add_tween('myapp.tween_factory2',
+ over=pyramid.tweens.MAIN,
+ under='myapp.tween_factory1')
The above example will generate an implicit tween chain that looks like this::
@@ -1357,17 +1361,17 @@ list of Python dotted names which will override the ordering (and inclusion) of
tween factories in the implicit tween chain. For example:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyApp
- pyramid.reload_templates = true
- pyramid.debug_authorization = false
- pyramid.debug_notfound = false
- pyramid.debug_routematch = false
- pyramid.debug_templates = true
- pyramid.tweens = myapp.my_cool_tween_factory
- pyramid.tweens.excview_tween_factory
+ [app:main]
+ use = egg:MyApp
+ pyramid.reload_templates = true
+ pyramid.debug_authorization = false
+ pyramid.debug_notfound = false
+ pyramid.debug_routematch = false
+ pyramid.debug_templates = true
+ pyramid.tweens = myapp.my_cool_tween_factory
+ pyramid.tweens.excview_tween_factory
In the above configuration, calls made during configuration to
:meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is
@@ -1594,7 +1598,7 @@ registered ``request_path_startswith`` predicate in a call to
# and at configuration time
config.add_subscriber(yosubscriber, NewRequest,
- request_path_startswith='/add_yo')
+ request_path_startswith='/add_yo')
Here's the same subscriber/predicate/event-type combination used via
:class:`~pyramid.events.subscriber`.
@@ -1726,24 +1730,24 @@ For example, below is a callable that can provide timing information for the
view pipeline:
.. code-block:: python
- :linenos:
+ :linenos:
- import time
+ import time
- def timing_view(view, info):
- if info.options.get('timed'):
- def wrapper_view(context, request):
- start = time.time()
- response = view(context, request)
- end = time.time()
- response.headers['X-View-Performance'] = '%.3f' % (end - start,)
- return response
- return wrapper_view
- return view
+ def timing_view(view, info):
+ if info.options.get('timed'):
+ def wrapper_view(context, request):
+ start = time.time()
+ response = view(context, request)
+ end = time.time()
+ response.headers['X-View-Performance'] = '%.3f' % (end - start,)
+ return response
+ return wrapper_view
+ return view
- timing_view.options = ('timed',)
+ timing_view.options = ('timed',)
- config.add_view_deriver(timing_view)
+ config.add_view_deriver(timing_view)
The setting of ``timed`` on the timing_view signifies to Pyramid that ``timed``
is a valid ``view_config`` keyword argument now. The ``timing_view`` custom
@@ -1753,20 +1757,20 @@ a ``timed=True`` value passed as one of its ``view_config`` keywords.
For example, this view configuration will *not* be a timed view:
.. code-block:: python
- :linenos:
+ :linenos:
- @view_config(route_name='home')
- def home(request):
- return Response('Home')
+ @view_config(route_name='home')
+ def home(request):
+ return Response('Home')
But this view *will* have timing information added to the response headers:
.. code-block:: python
- :linenos:
+ :linenos:
- @view_config(route_name='home', timed=True)
- def home(request):
- return Response('Home')
+ @view_config(route_name='home', timed=True)
+ def home(request):
+ return Response('Home')
View derivers are unique in that they have access to most of the options
passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index ff26d52ec..1238601ed 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -35,15 +35,15 @@ will often have statements like this within its application startup
configuration:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_route('foobar', '{foo}/{bar}')
- config.add_route('bazbuz', '{baz}/{buz}')
+ config.add_route('foobar', '{foo}/{bar}')
+ config.add_route('bazbuz', '{baz}/{buz}')
- config.add_view('myproject.views.foobar', route_name='foobar')
- config.add_view('myproject.views.bazbuz', route_name='bazbuz')
+ config.add_view('myproject.views.foobar', route_name='foobar')
+ config.add_view('myproject.views.bazbuz', route_name='bazbuz')
Each :term:`route` corresponds to one or more view callables. Each view
callable is associated with a route by passing a ``route_name`` parameter that
@@ -181,9 +181,9 @@ A hybrid application most often implies the inclusion of a route configuration
that contains the special token ``*traverse`` at the end of a route's pattern:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('home', '{foo}/{bar}/*traverse')
+ config.add_route('home', '{foo}/{bar}/*traverse')
A ``*traverse`` token at the end of the pattern in a route's configuration
implies a "remainder" *capture* value. When it is used, it will match the
@@ -217,31 +217,31 @@ application. To that end, let's imagine that we've created a root factory that
looks like so in a module named ``routes.py``:
.. code-block:: python
- :linenos:
+ :linenos:
- class Resource(object):
- def __init__(self, subobjects):
- self.subobjects = subobjects
+ class Resource(object):
+ def __init__(self, subobjects):
+ self.subobjects = subobjects
- def __getitem__(self, name):
- return self.subobjects[name]
+ def __getitem__(self, name):
+ return self.subobjects[name]
- root = Resource(
- {'a': Resource({'b': Resource({'c': Resource({})})})}
- )
+ root = Resource(
+ {'a': Resource({'b': Resource({'c': Resource({})})})}
+ )
- def root_factory(request):
- return root
+ def root_factory(request):
+ return root
Above we've defined a (bogus) resource tree that can be traversed, and a
``root_factory`` function that can be used as part of a particular route
configuration statement:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('home', '{foo}/{bar}/*traverse',
- factory='mypackage.routes.root_factory')
+ config.add_route('home', '{foo}/{bar}/*traverse',
+ factory='mypackage.routes.root_factory')
The ``factory`` above points at the function we've defined. It will return an
instance of the ``Resource`` class as a root object whenever this route is
@@ -286,11 +286,11 @@ configuration that will match when :term:`view lookup` is invoked after a route
matches:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('home', '{foo}/{bar}/*traverse',
- factory='mypackage.routes.root_factory')
- config.add_view('mypackage.views.myview', route_name='home')
+ config.add_route('home', '{foo}/{bar}/*traverse',
+ factory='mypackage.routes.root_factory')
+ config.add_view('mypackage.views.myview', route_name='home')
Note that the above call to :meth:`~pyramid.config.Configurator.add_view`
includes a ``route_name`` argument. View configurations that include a
@@ -316,13 +316,13 @@ It is also possible to declare alternative views that may be invoked when a
hybrid route is matched:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('home', '{foo}/{bar}/*traverse',
- factory='mypackage.routes.root_factory')
- config.add_view('mypackage.views.myview', route_name='home')
- config.add_view('mypackage.views.another_view', route_name='home',
- name='another')
+ config.add_route('home', '{foo}/{bar}/*traverse',
+ factory='mypackage.routes.root_factory')
+ config.add_view('mypackage.views.myview', route_name='home')
+ config.add_view('mypackage.views.another_view', route_name='home',
+ name='another')
The ``add_view`` call for ``mypackage.views.another_view`` above names a
different view and, more importantly, a different :term:`view name`. The above
@@ -361,10 +361,10 @@ Here's a use of the ``traverse`` pattern in a call to
:meth:`~pyramid.config.Configurator.add_route`:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('abc', '/articles/{article}/edit',
- traverse='/{article}')
+ config.add_route('abc', '/articles/{article}/edit',
+ traverse='/{article}')
The syntax of the ``traverse`` argument is the same as it is for ``pattern``.
@@ -404,10 +404,10 @@ though the view configuration statement does not have the ``route_name="abc"``
attribute.
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('abc', '/abc/*traverse', use_global_views=True)
- config.add_view('myproject.views.bazbuz', name='bazbuz')
+ config.add_route('abc', '/abc/*traverse', use_global_views=True)
+ config.add_view('myproject.views.bazbuz', name='bazbuz')
.. index::
pair: hybrid applications; *subpath
@@ -432,14 +432,14 @@ value of ``*subpath``. You'll see this pattern most commonly in route
declarations that look like this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.static import static_view
+ from pyramid.static import static_view
- www = static_view('mypackage:static', use_subpath=True)
+ www = static_view('mypackage:static', use_subpath=True)
- config.add_route('static', '/static/*subpath')
- config.add_view(www, route_name='static')
+ config.add_route('static', '/static/*subpath')
+ config.add_view(www, route_name='static')
``mypackage.views.www`` is an instance of :class:`pyramid.static.static_view`.
This effectively tells the static helper to traverse everything in the subpath
@@ -472,7 +472,7 @@ like so:
.. code-block:: python
- config.add_route('mysection', '/mysection*traverse')
+ config.add_route('mysection', '/mysection*traverse')
If you'd like to generate the URL ``http://example.com/mysection/a/``, you can
use the following incantation, assuming that the variable ``a`` below points to
@@ -480,13 +480,13 @@ a resource that is a child of the root with a ``__name__`` of ``a``:
.. code-block:: python
- request.resource_url(a, route_name='mysection')
+ request.resource_url(a, route_name='mysection')
You can generate only the path portion ``/mysection/a/`` assuming the same:
.. code-block:: python
- request.resource_path(a, route_name='mysection')
+ request.resource_path(a, route_name='mysection')
The path is virtual host aware, so if the ``X-Vhm-Root`` environment variable
is present in the request, and it's set to ``/a``, the above call to
@@ -501,13 +501,13 @@ the route definition is like so:
.. code-block:: python
- config.add_route('mysection', '/{id}/mysection*traverse')
+ config.add_route('mysection', '/{id}/mysection*traverse')
You can pass ``route_kw`` in to fill in ``{id}`` above:
.. code-block:: python
- request.resource_url(a, route_name='mysection', route_kw={'id':'1'})
+ request.resource_url(a, route_name='mysection', route_kw={'id':'1'})
If you pass ``route_kw`` but do not pass ``route_name``, ``route_kw`` will be
ignored.
@@ -521,13 +521,13 @@ following route:
.. code-block:: python
- config.add_route('mysection', '/mysection*subpath')
+ config.add_route('mysection', '/mysection*subpath')
You can fill in the ``*subpath`` value using ``resource_url`` by doing:
.. code-block:: python
- request.resource_path(a, route_name='mysection',
+ request.resource_path(a, route_name='mysection',
route_remainder_name='subpath')
If you pass ``route_remainder_name`` but do not pass ``route_name``,
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index 382b75b4a..9b838c7f4 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -44,10 +44,10 @@ The most primitive way to create a translation string is to use the
:class:`pyramid.i18n.TranslationString` callable:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString
- ts = TranslationString('Add')
+ from pyramid.i18n import TranslationString
+ ts = TranslationString('Add')
This creates a Unicode-like object that is a TranslationString.
@@ -66,20 +66,20 @@ object or an ASCII string. The msgid may optionally contain *replacement
markers*. For instance:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString
- ts = TranslationString('Add ${number}')
+ from pyramid.i18n import TranslationString
+ ts = TranslationString('Add ${number}')
Within the string above, ``${number}`` is a replacement marker. It will be
replaced by whatever is in the *mapping* for a translation string. The mapping
may be supplied at the same time as the replacement marker itself:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString
- ts = TranslationString('Add ${number}', mapping={'number':1})
+ from pyramid.i18n import TranslationString
+ ts = TranslationString('Add ${number}', mapping={'number':1})
Any number of replacement markers can be present in the msgid value, any number
of times. Only markers which can be replaced by the values in the *mapping*
@@ -91,11 +91,11 @@ represents a translation category to disambiguate it from other translations of
the same msgid, in case they conflict.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString
- ts = TranslationString('Add ${number}', mapping={'number':1},
- domain='form')
+ from pyramid.i18n import TranslationString
+ ts = TranslationString('Add ${number}', mapping={'number':1},
+ domain='form')
The above translation string named a domain of ``form``. A :term:`translator`
function will often use the domain to locate the right translator file on the
@@ -106,7 +106,7 @@ like this one:
.. code-block:: text
- locale/de/LC_MESSAGES/form.mo
+ locale/de/LC_MESSAGES/form.mo
In other words, it would want to take translations from the ``form.mo``
translation file in the German language.
@@ -120,10 +120,10 @@ files, so it is often useful to create translation strings with "opaque"
message identifiers unrelated to their default text:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString
- ts = TranslationString('add-number', default='Add ${number}',
+ from pyramid.i18n import TranslationString
+ ts = TranslationString('add-number', default='Add ${number}',
domain='form', mapping={'number':1})
When default text is used, Default text objects may contain replacement values.
@@ -141,11 +141,11 @@ the ``domain`` value of any :term:`translation string` generated by using it.
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationStringFactory
- _ = TranslationStringFactory('pyramid')
- ts = _('add-number', default='Add ${number}', mapping={'number':1})
+ from pyramid.i18n import TranslationStringFactory
+ _ = TranslationStringFactory('pyramid')
+ ts = _('add-number', default='Add ${number}', mapping={'number':1})
.. note:: We assigned the translation string factory to the name ``_``. This
is a convention which will be supported by translation file generation
@@ -161,11 +161,11 @@ resulting translation string will be ``pyramid``. As a result, the previous
code example is completely equivalent (except for spelling) to:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString as _
- ts = _('add-number', default='Add ${number}', mapping={'number':1},
- domain='pyramid')
+ from pyramid.i18n import TranslationString as _
+ ts = _('add-number', default='Add ${number}', mapping={'number':1},
+ domain='pyramid')
You can set up your own translation string factory much like the one provided
above by using the :class:`~pyramid.i18n.TranslationStringFactory` class. For
@@ -174,11 +174,11 @@ example, if you'd like to create a translation string factory which presets the
something like this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationStringFactory
- _ = TranslationStringFactory('form')
- ts = _('add-number', default='Add ${number}', mapping={'number':1})
+ from pyramid.i18n import TranslationStringFactory
+ _ = TranslationStringFactory('form')
+ ts = _('add-number', default='Add ${number}', mapping={'number':1})
Creating a unique domain for your application via a translation string factory
is best practice. Using your own unique translation domain allows another
@@ -256,10 +256,10 @@ In order for the commands related to working with ``gettext`` translation files
to work properly, you will need to have :term:`Lingua` and :term:`Gettext`
installed into the same environment in which :app:`Pyramid` is installed.
-Installation on UNIX
+Installation on Unix
++++++++++++++++++++
-Gettext is often already installed on UNIX systems. You can check if it is
+Gettext is often already installed on Unix systems. You can check if it is
installed by testing if the ``msgfmt`` command is available. If it is not
available you can install it through the packaging system from your OS; the
package name is almost always ``gettext``. For example on a Debian or Ubuntu
@@ -267,7 +267,7 @@ system run this command:
.. code-block:: bash
- $ sudo apt-get install gettext
+ sudo apt-get install gettext
Installing Lingua is done with the Python packaging tools. If the
:term:`virtual environment` into which you've installed your :app:`Pyramid`
@@ -276,7 +276,7 @@ like so:
.. code-block:: bash
- $ $VENV/bin/pip install lingua
+ $VENV/bin/pip install lingua
Installation on Windows
+++++++++++++++++++++++
@@ -294,7 +294,7 @@ Lingua like so:
.. code-block:: doscon
- c:\> %VENV%\Scripts\pip install lingua
+ %VENV%\Scripts\pip install lingua
.. index::
@@ -311,9 +311,9 @@ application. You run a ``pot-create`` command to extract the messages:
.. code-block:: bash
- $ cd /file/path/to/myapplication_setup.py
- $ mkdir -p myapplication/locale
- $ $VENV/bin/pot-create -o myapplication/locale/myapplication.pot src
+ cd /file/path/to/myapplication_setup.py
+ mkdir -p myapplication/locale
+ $VENV/bin/pot-create -o myapplication/locale/myapplication.pot src
The message catalog ``.pot`` template will end up in
``myapplication/locale/myapplication.pot``.
@@ -334,10 +334,10 @@ template by using the ``msginit`` command from Gettext:
.. code-block:: bash
- $ cd /file/path/to/myapplication_setup.py
- $ cd myapplication/locale
- $ mkdir -p es/LC_MESSAGES
- $ msginit -l es -o es/LC_MESSAGES/myapplication.po
+ cd /file/path/to/myapplication_setup.py
+ cd myapplication/locale
+ mkdir -p es/LC_MESSAGES
+ msginit -l es -o es/LC_MESSAGES/myapplication.po
This will create a new message catalog ``.po`` file in
``myapplication/locale/es/LC_MESSAGES/myapplication.po``.
@@ -365,9 +365,9 @@ the ``msgmerge`` command from Gettext.
.. code-block:: bash
- $ cd /file/path/to/myapplication_setup.py
- $ cd myapplication/locale
- $ msgmerge --update es/LC_MESSAGES/myapplication.po myapplication.pot
+ cd /file/path/to/myapplication_setup.py
+ cd myapplication/locale
+ msgmerge --update es/LC_MESSAGES/myapplication.po myapplication.pot
.. index::
pair: compiling; message catalog
@@ -383,9 +383,9 @@ Gettext:
.. code-block:: bash
- $ cd /file/path/to/myapplication_setup.py
- $ msgfmt -o myapplication/locale/es/LC_MESSAGES/myapplication.mo \
- myapplication/locale/es/LC_MESSAGES/myapplication.po
+ cd /file/path/to/myapplication_setup.py
+ msgfmt -o myapplication/locale/es/LC_MESSAGES/myapplication.mo \
+ myapplication/locale/es/LC_MESSAGES/myapplication.po
This will create a ``.mo`` file for each ``.po`` file in your application. As
long as the :term:`translation directory` in which the ``.mo`` file ends up in
@@ -409,10 +409,10 @@ translations implied by the active :term:`locale negotiator`, or a default
localizer object if no explicit locale negotiator is registered.
.. code-block:: python
- :linenos:
+ :linenos:
- def aview(request):
- localizer = request.localizer
+ def aview(request):
+ localizer = request.localizer
.. note::
@@ -433,17 +433,17 @@ object representing the translation. Generating a translation in a view
component of an application might look like so:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import TranslationString
+ from pyramid.i18n import TranslationString
- ts = TranslationString('Add ${number}', mapping={'number':1},
- domain='pyramid')
+ ts = TranslationString('Add ${number}', mapping={'number':1},
+ domain='pyramid')
- def aview(request):
- localizer = request.localizer
- translated = localizer.translate(ts) # translation string
- # ... use translated ...
+ def aview(request):
+ localizer = request.localizer
+ translated = localizer.translate(ts) # translation string
+ # ... use translated ...
The ``request.localizer`` attribute will be a :class:`pyramid.i18n.Localizer`
object bound to the locale name represented by the request. The translation
@@ -467,22 +467,22 @@ Performing a Pluralization
A :term:`localizer` has a ``pluralize`` method with the following signature:
.. code-block:: python
- :linenos:
+ :linenos:
- def pluralize(singular, plural, n, domain=None, mapping=None):
- ...
+ def pluralize(singular, plural, n, domain=None, mapping=None):
+ # ...
The simplest case is the ``singular`` and ``plural`` arguments being passed as
Unicode literals. This returns the appropriate literal according to the locale
pluralization rules for the number ``n``, and interpolates ``mapping``.
.. code-block:: python
- :linenos:
+ :linenos:
- def aview(request):
- localizer = request.localizer
- translated = localizer.pluralize('Item', 'Items', 1, 'mydomain')
- # ... use translated ...
+ def aview(request):
+ localizer = request.localizer
+ translated = localizer.pluralize('Item', 'Items', 1, 'mydomain')
+ # ... use translated ...
However, for support of other languages, the ``singular`` argument should be a
Unicode value representing a :term:`message identifier`. In this case the
@@ -499,13 +499,13 @@ The argument provided as ``singular`` may be a :term:`translation string`
object, but the domain and mapping information attached is ignored.
.. code-block:: python
- :linenos:
+ :linenos:
- def aview(request):
- localizer = request.localizer
- num = 1
- translated = localizer.pluralize('item_plural', '${number} items',
- num, 'mydomain', mapping={'number':num})
+ def aview(request):
+ localizer = request.localizer
+ num = 1
+ translated = localizer.pluralize('item_plural', '${number} items',
+ num, 'mydomain', mapping={'number':num})
The corresponding message catalog must have language plural definitions and
plural alternatives set.
@@ -537,10 +537,10 @@ You can obtain the locale name related to a request by using the
:func:`pyramid.request.Request.locale_name` attribute of the request.
.. code-block:: python
- :linenos:
+ :linenos:
- def aview(request):
- locale_name = request.locale_name
+ def aview(request):
+ locale_name = request.locale_name
The locale name of a request is dynamically computed; it will be the locale
name negotiated by the currently active :term:`locale negotiator`, or the
@@ -555,22 +555,22 @@ without invoking the :term:`locale negotiator`. To avoid this caching, you can
use the :func:`pyramid.i18n.negotiate_locale_name` function:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.i18n import negotiate_locale_name
+ from pyramid.i18n import negotiate_locale_name
- def aview(request):
- locale_name = negotiate_locale_name(request)
+ def aview(request):
+ locale_name = negotiate_locale_name(request)
You can also obtain the locale name related to a request using the
``locale_name`` attribute of a :term:`localizer`.
.. code-block:: python
- :linenos:
+ :linenos:
- def aview(request):
- localizer = request.localizer
- locale_name = localizer.locale_name
+ def aview(request):
+ localizer = request.localizer
+ locale_name = localizer.locale_name
Obtaining the locale name as an attribute of a localizer is equivalent to
obtaining a locale name by asking for the
@@ -597,13 +597,13 @@ locale name for a request to pass to the :class:`babel.core.Locale`
constructor. See :ref:`obtaining_the_locale_name`. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from babel.core import Locale
+ from babel.core import Locale
- def aview(request):
- locale_name = request.locale_name
- locale = Locale(locale_name)
+ def aview(request):
+ locale_name = request.locale_name
+ locale = Locale(locale_name)
.. index::
pair: translation strings; Chameleon
@@ -623,24 +623,24 @@ For example, in a Chameleon ZPT template, the translation string represented by
before being rendered:
.. code-block:: xml
- :linenos:
+ :linenos:
- <span tal:content="some_translation_string"/>
+ <span tal:content="some_translation_string"/>
.. code-block:: xml
- :linenos:
+ :linenos:
- <span tal:replace="some_translation_string"/>
+ <span tal:replace="some_translation_string"/>
.. code-block:: xml
- :linenos:
+ :linenos:
- <span>${some_translation_string}</span>
+ <span>${some_translation_string}</span>
.. code-block:: xml
- :linenos:
+ :linenos:
- <a tal:attributes="href some_translation_string">Click here</a>
+ <a tal:attributes="href some_translation_string">Click here</a>
.. XXX the last example above appears to not yet work as of Chameleon
.. 1.2.3
@@ -701,23 +701,23 @@ setting. This value represents the :term:`default locale name` used when the
:mod:`~pyramid.config.Configurator` constructor at startup time:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- config = Configurator(settings={'pyramid.default_locale_name':'de'})
+ from pyramid.config import Configurator
+ config = Configurator(settings={'pyramid.default_locale_name':'de'})
You may alternately supply a ``pyramid.default_locale_name`` via an
application's ``.ini`` file:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyProject
- pyramid.reload_templates = true
- pyramid.debug_authorization = false
- pyramid.debug_notfound = false
- pyramid.default_locale_name = de
+ [app:main]
+ use = egg:MyProject
+ pyramid.reload_templates = true
+ pyramid.debug_authorization = false
+ pyramid.debug_notfound = false
+ pyramid.default_locale_name = de
If this value is not supplied via the Configurator constructor or via a config
file, it will default to ``en``.
@@ -726,11 +726,11 @@ If this setting is supplied within the :app:`Pyramid` application ``.ini``
file, it will be available as a settings key:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.threadlocal import get_current_registry
- settings = get_current_registry().settings
- default_locale_name = settings['pyramid.default_locale_name']
+ from pyramid.threadlocal import get_current_registry
+ settings = get_current_registry().settings
+ default_locale_name = settings['pyramid.default_locale_name']
.. index::
single: detecting languages
@@ -768,23 +768,23 @@ on convention by using the :mod:`pyramid.settings` mechanism.
Allow a deployer to modify your application's ``.ini`` file:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyProject
- # ...
- available_languages = fr de en ru
+ [app:main]
+ use = egg:MyProject
+ # ...
+ available_languages = fr de en ru
Then as a part of the code of a custom :term:`locale negotiator`:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.settings import aslist
+ from pyramid.settings import aslist
- def my_locale_negotiator(request):
- languages = aslist(request.registry.settings['available_languages'])
- # ...
+ def my_locale_negotiator(request):
+ languages = aslist(request.registry.settings['available_languages'])
+ # ...
This is only a suggestion. You can create your own "available languages"
configuration scheme as necessary.
@@ -836,11 +836,11 @@ You can add a translation directory imperatively by using the
startup. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- config.add_translation_dirs('my.application:locale/',
- 'another.application:locale/')
+ from pyramid.config import Configurator
+ config.add_translation_dirs('my.application:locale/',
+ 'another.application:locale/')
A message catalog in a translation directory added via
:meth:`~pyramid.config.Configurator.add_translation_dirs` will be merged into
@@ -955,10 +955,10 @@ configuration by passing an object which can act as the negotiator (or a
instance during application startup. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- config = Configurator(locale_negotiator=my_locale_negotiator)
+ from pyramid.config import Configurator
+ config = Configurator(locale_negotiator=my_locale_negotiator)
Alternatively, use the
:meth:`pyramid.config.Configurator.set_locale_negotiator` method.
@@ -966,8 +966,8 @@ Alternatively, use the
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- config = Configurator()
- config.set_locale_negotiator(my_locale_negotiator)
+ from pyramid.config import Configurator
+ config = Configurator()
+ config.set_locale_negotiator(my_locale_negotiator)
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index a9ec68d61..80d5ea3de 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -24,8 +24,8 @@ the following sections.
As of this writing, :app:`Pyramid` is tested against Python 2.7,
Python 3.4, Python 3.5, Python 3.6, and PyPy.
-:app:`Pyramid` is known to run on all popular UNIX-like systems such as Linux,
-Mac OS X, and FreeBSD, as well as on Windows platforms. It is also known to
+:app:`Pyramid` is known to run on all popular Unix-like systems such as Linux,
+macOS, and FreeBSD, as well as on Windows platforms. It is also known to
run on :term:`PyPy` (1.9+).
:app:`Pyramid` installation does not require the compilation of any C code.
@@ -42,24 +42,24 @@ instead.
compiler and the Python header files installed for your operating system.
-.. _for-mac-os-x-users:
+.. _for-macos-users:
-For Mac OS X Users
-~~~~~~~~~~~~~~~~~~
+For macOS Users
+~~~~~~~~~~~~~~~
-Python comes pre-installed on Mac OS X, but due to Apple's release cycle, it is
+Python comes pre-installed on macOS, 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 version of Python for Mac OS X from the binaries on
+You can install the latest version of Python for macOS from the binaries on
`python.org <https://www.python.org/downloads/mac-osx/>`_.
Alternatively, you can use the `homebrew <https://brew.sh/>`_ package manager.
-.. code-block:: text
+.. code-block:: bash
- # for python 3.x
- $ brew install python3
+ # for python 3.x
+ brew install python3
If you use an installer for your Python, then you can skip to the section
:ref:`installing_unix`.
@@ -67,12 +67,12 @@ If you use an installer for your Python, then you can skip to the section
.. _if-you-don-t-yet-have-a-python-interpreter-unix:
-If You Don't Yet Have a Python Interpreter (UNIX)
+If You Don't Yet Have a Python Interpreter (Unix)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If your system doesn't have a Python interpreter, and you're on UNIX, you can
+If your system doesn't have a Python interpreter, and you're on Unix, you can
either install Python using your operating system's package manager *or* you
-can install Python from source fairly easily on any UNIX system that has
+can install Python from source fairly easily on any Unix system that has
development tools.
.. seealso:: See the official Python documentation :ref:`Using Python on Unix
@@ -162,15 +162,15 @@ application, rather than being installed system wide.
.. index::
- single: installing on UNIX
- single: installing on Mac OS X
+ single: installing on Unix
+ single: installing on macOS
.. _installing_unix:
-Installing :app:`Pyramid` on a UNIX System
+Installing :app:`Pyramid` on a Unix System
------------------------------------------
-After installing Python as described previously in :ref:`for-mac-os-x-users` or
+After installing Python as described previously in :ref:`for-macos-users` or
:ref:`if-you-don-t-yet-have-a-python-interpreter-unix`, and satisfying the
:ref:`requirements-for-installing-packages`, you can now install Pyramid.
@@ -178,8 +178,8 @@ After installing Python as described previously in :ref:`for-mac-os-x-users` or
.. code-block:: bash
- $ export VENV=~/env
- $ python3 -m venv $VENV
+ export VENV=~/env
+ python3 -m venv $VENV
You can either follow the use of the environment variable ``$VENV``, or
replace it with the root directory of the virtual environment. If you choose
@@ -193,7 +193,7 @@ After installing Python as described previously in :ref:`for-mac-os-x-users` or
.. parsed-literal::
- $ $VENV/bin/pip install "pyramid==\ |release|\ "
+ $VENV/bin/pip install "pyramid==\ |release|\ "
.. index::
single: $VENV/bin/pip vs. source bin/activate
@@ -233,10 +233,10 @@ After installing Python as described previously in
.. code-block:: doscon
- c:\> cd \
- c:\> set VENV=c:\env
- c:\> python -m venv %VENV%
- c:\> cd %VENV%
+ cd \
+ set VENV=c:\env
+ python -m venv %VENV%
+ cd %VENV%
You can either follow the use of the environment variable ``%VENV%``, or
replace it with the root directory of the virtual environment. If you choose
@@ -250,7 +250,7 @@ After installing Python as described previously in
.. parsed-literal::
- c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ "
+ %VENV%\\Scripts\\pip install "pyramid==\ |release|\ "
.. note:: See the note above for :ref:`Why use $VENV/bin/pip instead of source
bin/activate, then pip <venv-bin-pip-vs-source-bin-activate>`.
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index a09900950..3ee6b5367 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -104,12 +104,12 @@ Configure applications with decorators
.. code-block:: python
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='fred')
- def fred_view(request):
- return Response('fred')
+ @view_config(route_name='fred')
+ def fred_view(request):
+ return Response('fred')
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.
@@ -183,34 +183,34 @@ A fundamental task for any framework is to map URLs to code. In :app:`Pyramid`,
Here's a view callable defined as a function:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config(route_name='aview')
- def aview(request):
- return Response('one')
+ @view_config(route_name='aview')
+ def aview(request):
+ return Response('one')
Here's a few views defined as methods of a class instead:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- class AView(object):
- def __init__(self, request):
- self.request = request
+ class AView(object):
+ def __init__(self, request):
+ self.request = request
- @view_config(route_name='view_one')
- def view_one(self):
- return Response('one')
+ @view_config(route_name='view_one')
+ def view_one(self):
+ return Response('one')
- @view_config(route_name='view_two')
- def view_two(self):
- return Response('two')
+ @view_config(route_name='view_two')
+ def view_two(self):
+ return Response('two')
.. seealso::
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
index c9fecd4f4..50f4ac736 100644
--- a/docs/narr/introspector.rst
+++ b/docs/narr/introspector.rst
@@ -611,8 +611,8 @@ application setup:
.. code-block:: python
- from pyramid.config import Configurator
- config = Configurator(..., introspection=False)
+ from pyramid.config import Configurator
+ config = Configurator(..., introspection=False)
When ``introspection`` is ``False``, all introspectables generated by
configuration directives are thrown away.
diff --git a/docs/narr/logging.rst b/docs/narr/logging.rst
index b21fe1314..ce83cd3ee 100644
--- a/docs/narr/logging.rst
+++ b/docs/narr/logging.rst
@@ -65,7 +65,7 @@ In this logging configuration:
.. code-block:: text
- 2007-08-17 15:04:08,704 INFO [packagename] Loading resource, id: 86
+ 2007-08-17 15:04:08,704 INFO [packagename] Loading resource, id: 86
- 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.
@@ -276,7 +276,7 @@ function of your project's ``__init__`` file:
.. code-block:: python
- ...
+ # ...
app = config.make_wsgi_app()
from paste.translogger import TransLogger
app = TransLogger(app, setup_console_handler=False)
@@ -298,7 +298,7 @@ output to the console when we request a page:
(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 - "-"
- "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725
+ "Mozilla/5.0 (Macintosh; U; Intel macOS; en-US; rv:1.8.1.6) Gecko/20070725
Firefox/2.0.0.6"
To direct TransLogger to an ``access.log`` FileHandler, we need the following
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 1cd36dbf6..f41e155e7 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -85,7 +85,7 @@ On all platforms, generate a project using cookiecutter.
.. code-block:: bash
- $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
+ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -103,31 +103,31 @@ If prompted for the first item, accept the default ``yes`` by hitting return.
We then run through the following commands.
-On UNIX:
+On Unix:
.. code-block:: bash
# Reset our environment variable for a new virtual environment.
- $ export VENV=~/env/myproject/env
+ export VENV=~/env/myproject/env
# Change directory into your newly created project.
- $ cd myproject
+ cd myproject
# Create a new virtual environment...
- $ python3 -m venv $VENV
+ python3 -m venv $VENV
# ...where we upgrade packaging tools.
- $ env/bin/pip install --upgrade pip setuptools
+ env/bin/pip install --upgrade pip setuptools
Or on Windows:
.. code-block:: doscon
# Reset our environment variable for a new virtual environment.
- c:\> set VENV=c:\env\myproject\env
+ set VENV=c:\env\myproject\env
# Change directory into your newly created project.
- c:\> cd myproject
+ cd myproject
# Create a new virtual environment...
- c:\myproject> python -m venv %VENV%
+ python -m venv %VENV%
# ...where we upgrade packaging tools.
- c:\myproject> %VENV%\Scripts\pip install --upgrade pip setuptools
+ %VENV%\Scripts\pip install --upgrade pip setuptools
As a result of invoking the ``cookiecutter`` command, a directory named
``myproject`` is created. That directory is a :term:`project` directory. The
@@ -188,23 +188,23 @@ in the ``bin`` (or ``Scripts`` on Windows) directory of your virtual Python
environment. Your terminal's current working directory *must* be the newly
created project directory.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
Or on Windows:
.. code-block:: doscon
- c:\env\myproject> %VENV%\Scripts\pip install -e .
+ %VENV%\Scripts\pip install -e .
-Elided output from a run of this command on UNIX is shown below:
+Elided output from a run of this command on Unix is shown below:
.. code-block:: bash
- Running setup.py develop for myproject
+ Running setup.py develop for myproject
Successfully installed Jinja2-2.8 Mako-1.0.6 MarkupSafe-0.23 \
PasteDeploy-1.5.2 Pygments-2.1.3 WebOb-1.7.0 myproject pyramid-1.7.3 \
pyramid-debugtoolbar-3.0.5 pyramid-jinja2-2.7 pyramid-mako-1.0.2 \
@@ -226,41 +226,41 @@ Running the Tests for Your Application
To run unit tests for your application, you must first install the testing
dependencies.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/pip install -e ".[testing]"
+ $VENV/bin/pip install -e ".[testing]"
On Windows:
.. code-block:: doscon
- c:\env\myproject> %VENV%\Scripts\pip install -e ".[testing]"
+ %VENV%\Scripts\pip install -e ".[testing]"
Once the testing requirements are installed, then you can run the tests using
the ``py.test`` command that was just installed in the ``bin`` directory of
your virtual environment.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/py.test -q
+ $VENV/bin/py.test -q
On Windows:
.. code-block:: doscon
- c:\env\myproject> %VENV%\Scripts\py.test -q
+ %VENV%\Scripts\py.test -q
-Here's sample output from a test run on UNIX:
+Here's sample output from a test run on Unix:
.. code-block:: bash
- $ $VENV/bin/py.test -q
- ..
- 2 passed in 0.47 seconds
+ $VENV/bin/py.test -q
+ ..
+ 2 passed in 0.47 seconds
The tests themselves are found in the ``tests.py`` module in your ``cookiecutter``-generated project. Within a project generated by the ``pyramid-cookiecutter-starter`` cookiecutter, only two sample tests exist.
@@ -275,7 +275,7 @@ to ``py.test``:
.. code-block:: bash
- $ $VENV/bin/py.test --cov -q
+ $VENV/bin/py.test --cov -q
Cookiecutters include configuration defaults for ``py.test`` and test coverage.
These configuration files are ``pytest.ini`` and ``.coveragerc``, located at
@@ -284,7 +284,7 @@ path to the module on which we want to run tests and coverage.
.. code-block:: bash
- $ $VENV/bin/py.test --cov=myproject myproject/tests.py -q
+ $VENV/bin/py.test --cov=myproject myproject/tests.py -q
.. seealso:: See py.test's documentation for :ref:`pytest:usage` or invoke
``py.test -h`` to see its full set of options.
@@ -307,26 +307,26 @@ Once a project is installed for development, you can run the application it
represents using the ``pserve`` command against the generated configuration
file. In our case, this file is named ``development.ini``.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini
+ $VENV/bin/pserve development.ini
On Windows:
.. code-block:: doscon
- c:\env\myproject> %VENV%\Scripts\pserve development.ini
+ %VENV%\Scripts\pserve development.ini
-Here's sample output from a run of ``pserve`` on UNIX:
+Here's sample output from a run of ``pserve`` on Unix:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini
- Starting server in PID 77171.
- Serving on http://localhost:6543
- Serving on http://localhost:6543
+ $VENV/bin/pserve development.ini
+ Starting server in PID 77171.
+ Serving on http://localhost:6543
+ Serving on http://localhost:6543
Access is restricted such that only a browser running on the same machine as
Pyramid will be able to access your Pyramid application. However, if you want
@@ -337,9 +337,9 @@ to open access to other machines on the same network, then edit the
.. code-block:: ini
- [server:main]
- use = egg:waitress#main
- listen = *:6543
+ [server:main]
+ use = egg:waitress#main
+ listen = *:6543
Now when you use ``pserve`` to start the application, it will respond to
requests on *all* IP addresses possessed by your system, not just requests to
@@ -394,26 +394,26 @@ module your project uses will cause the server to restart. This typically
makes development easier, as changes to Python code made within a
:app:`Pyramid` application is not put into effect until the server restarts.
-For example, on UNIX:
+For example, on Unix:
.. code-block:: text
- $ $VENV/bin/pserve development.ini --reload
- Starting subprocess with file monitor
- Starting server in PID 16601.
- Serving on http://localhost:6543
- Serving on http://localhost:6543
+ $VENV/bin/pserve development.ini --reload
+ Starting subprocess with file monitor
+ Starting server in PID 16601.
+ Serving on http://localhost:6543
+ Serving on http://localhost:6543
Now if you make a change to any of your project's ``.py`` files or ``.ini``
files, you'll see the server restart automatically:
.. code-block:: text
- development.ini changed; reloading...
- -------------------- Restarting --------------------
- Starting server in PID 16602.
- Serving on http://localhost:6543
- Serving on http://localhost:6543
+ development.ini changed; reloading...
+ -------------------- Restarting --------------------
+ Starting server in PID 16602.
+ Serving on http://localhost:6543
+ Serving on http://localhost:6543
Changes to template files (such as ``.pt`` or ``.mak`` files) won't cause the
server to restart. Changes to template files don't require a server restart as
@@ -466,9 +466,9 @@ like this to enable the toolbar when your system contacts Pyramid:
.. code-block:: ini
- [app:main]
- # .. other settings ...
- debugtoolbar.hosts = 192.168.1.1
+ [app:main]
+ # .. other settings ...
+ debugtoolbar.hosts = 192.168.1.1
For more information about what the debug toolbar allows you to do, see the
:ref:`documentation for pyramid_debugtoolbar <toolbar:overview>`.
@@ -481,22 +481,22 @@ You can also turn the debug toolbar off by editing ``development.ini`` and
commenting out a line. For example, instead of:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- # ... elided configuration
- pyramid.includes =
- pyramid_debugtoolbar
+ [app:main]
+ # ... elided configuration
+ pyramid.includes =
+ pyramid_debugtoolbar
Put a hash mark at the beginning of the ``pyramid_debugtoolbar`` line:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- # ... elided configuration
- pyramid.includes =
- # pyramid_debugtoolbar
+ [app:main]
+ # ... elided configuration
+ pyramid.includes =
+ # pyramid_debugtoolbar
Then restart the application to see that the toolbar has been turned off.
@@ -507,7 +507,7 @@ this:
.. code-block:: text
- ImportError: No module named #pyramid_debugtoolbar
+ ImportError: No module named #pyramid_debugtoolbar
.. index::
single: project structure
@@ -525,26 +525,26 @@ The ``myproject`` project we've generated has the following directory structure:
.. code-block:: text
- myproject/
- ├── .coveragerc
- ├── CHANGES.txt
- ├── MANIFEST.in
- ├── myproject
- │   ├── __init__.py
- │   ├── static
- │   │   ├── pyramid-16x16.png
- │   │   ├── pyramid.png
- │   │   └── theme.css
- │   ├── templates
- │   │   ├── layout.jinja2
- │   │   └── mytemplate.jinja2
- │   ├── tests.py
- │   └── views.py
- ├── README.txt
- ├── development.ini
- ├── production.ini
- ├── pytest.ini
- └── setup.py
+ myproject/
+ ├── .coveragerc
+ ├── CHANGES.txt
+ ├── MANIFEST.in
+ ├── myproject
+ │   ├── __init__.py
+ │   ├── static
+ │   │   ├── pyramid-16x16.png
+ │   │   ├── pyramid.png
+ │   │   └── theme.css
+ │   ├── templates
+ │   │   ├── layout.jinja2
+ │   │   └── mytemplate.jinja2
+ │   ├── tests.py
+ │   └── views.py
+ ├── README.txt
+ ├── development.ini
+ ├── production.ini
+ ├── pytest.ini
+ └── setup.py
The ``myproject`` :term:`Project`
@@ -785,7 +785,7 @@ you can try this command now:
.. code-block:: text
- $ $VENV/bin/python setup.py sdist
+ $VENV/bin/python setup.py sdist
This will create a tarball of your application in a ``dist`` subdirectory named
``myproject-0.0.tar.gz``. You can send this tarball to other people who want
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index e06c78028..493f808d5 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -9,13 +9,13 @@ interface, :app:`Pyramid` will attempt to use a :term:`renderer` to construct a
response. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='json')
- def hello_world(request):
- return {'content':'Hello!'}
+ @view_config(renderer='json')
+ def hello_world(request):
+ return {'content':'Hello!'}
The above example returns a *dictionary* from the view callable. A dictionary
does not implement the Pyramid response interface, so you might believe that
@@ -64,7 +64,7 @@ with a view callable:
.. code-block:: python
- config.add_view('myproject.views.my_view', renderer='json')
+ config.add_view('myproject.views.my_view', renderer='json')
When this configuration is added to an application, the
``myproject.views.my_view`` view callable will now use a ``json`` renderer,
@@ -85,39 +85,39 @@ renderer associated with the view configuration is ignored, and the response is
passed back to :app:`Pyramid` unchanged. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config(renderer='json')
- def view(request):
- return Response('OK') # json renderer avoided
+ @view_config(renderer='json')
+ def view(request):
+ return Response('OK') # json renderer avoided
Likewise for an :term:`HTTP exception` response:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPFound
- from pyramid.view import view_config
+ from pyramid.httpexceptions import HTTPFound
+ from pyramid.view import view_config
- @view_config(renderer='json')
- def view(request):
- return HTTPFound(location='http://example.com') # json renderer avoided
+ @view_config(renderer='json')
+ def view(request):
+ return HTTPFound(location='http://example.com') # json renderer avoided
You can of course also return the ``request.response`` attribute instead to
avoid rendering:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='json')
- def view(request):
- request.response.body = 'OK'
- return request.response # json renderer avoided
+ @view_config(renderer='json')
+ def view(request):
+ request.response.body = 'OK'
+ return request.response # json renderer avoided
.. index::
single: renderers (built-in)
@@ -153,20 +153,20 @@ renderer is specified in the configuration for this view, the view will render
the returned dictionary to the ``str()`` representation of the dictionary:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='string')
- def hello_world(request):
- return {'content':'Hello!'}
+ @view_config(renderer='string')
+ def hello_world(request):
+ return {'content':'Hello!'}
The body of the response returned by such a view will be a string representing
the ``str()`` serialization of the return value:
.. code-block:: python
- {'content': 'Hello!'}
+ {'content': 'Hello!'}
Views which use the string renderer can vary non-body response attributes by
using the API of the ``request.response`` attribute. See
@@ -190,20 +190,20 @@ renderer is specified in the configuration for this view, the view will render
the returned dictionary to a JSON serialization:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='json')
- def hello_world(request):
- return {'content':'Hello!'}
+ @view_config(renderer='json')
+ def hello_world(request):
+ return {'content':'Hello!'}
The body of the response returned by such a view will be a string representing
the JSON serialization of the return value:
.. code-block:: python
- {"content": "Hello!"}
+ {"content": "Hello!"}
The return value needn't be a dictionary, but the return value must contain
values serializable by the configured serializer (by default ``json.dumps``).
@@ -213,12 +213,12 @@ You can configure a view to use the JSON renderer by naming ``json`` as the
:meth:`~pyramid.config.Configurator.add_view`:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_view('myproject.views.hello_world',
- name='hello',
- context='myproject.resources.Hello',
- renderer='json')
+ config.add_view('myproject.views.hello_world',
+ name='hello',
+ context='myproject.resources.Hello',
+ renderer='json')
Views which use the JSON renderer can vary non-body response attributes by
using the API of the ``request.response`` attribute. See
@@ -248,23 +248,23 @@ forth). It should accept a single additional argument, ``request``, which will
be the active request object at render time.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- class MyObject(object):
- def __init__(self, x):
- self.x = x
+ class MyObject(object):
+ def __init__(self, x):
+ self.x = x
- def __json__(self, request):
- return {'x':self.x}
+ def __json__(self, request):
+ return {'x':self.x}
- @view_config(renderer='json')
- def objects(request):
- return [MyObject(1), MyObject(2)]
+ @view_config(renderer='json')
+ def objects(request):
+ return [MyObject(1), MyObject(2)]
- # the JSON value returned by ``objects`` will be:
- # [{"x": 1}, {"x": 2}]
+ # the JSON value returned by ``objects`` will be:
+ # [{"x": 1}, {"x": 2}]
Using the ``add_adapter`` Method of a Custom JSON Renderer
**********************************************************
@@ -279,17 +279,17 @@ custom types. The renderer will attempt to adapt non-serializable objects using
the registered adapters. A short example follows:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import JSON
+ from pyramid.renderers import JSON
- if __name__ == '__main__':
- config = Configurator()
- json_renderer = JSON()
- def datetime_adapter(obj, request):
- return obj.isoformat()
- json_renderer.add_adapter(datetime.datetime, datetime_adapter)
- config.add_renderer('json', json_renderer)
+ if __name__ == '__main__':
+ config = Configurator()
+ json_renderer = JSON()
+ def datetime_adapter(obj, request):
+ return obj.isoformat()
+ json_renderer.add_adapter(datetime.datetime, datetime_adapter)
+ config.add_renderer('json', json_renderer)
The ``add_adapter`` method should accept two arguments: the *class* of the
object that you want this adapter to run for (in the example above,
@@ -327,11 +327,11 @@ Unlike other renderers, a JSONP renderer needs to be configured at startup time
.. code-block:: python
- from pyramid.config import Configurator
- from pyramid.renderers import JSONP
+ from pyramid.config import Configurator
+ from pyramid.renderers import JSONP
- config = Configurator()
- config.add_renderer('jsonp', JSONP(param_name='callback'))
+ config = Configurator()
+ config.add_renderer('jsonp', JSONP(param_name='callback'))
Once this renderer is registered via
:meth:`~pyramid.config.Configurator.add_renderer` as above, you can use
@@ -340,11 +340,11 @@ Once this renderer is registered via
.. code-block:: python
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='jsonp')
- def myview(request):
- return {'greeting':'Hello world'}
+ @view_config(renderer='jsonp')
+ def myview(request):
+ return {'greeting':'Hello world'}
When a view is called that uses a JSONP renderer:
@@ -366,12 +366,12 @@ For example (JavaScript):
.. code-block:: javascript
- var api_url = 'http://api.geonames.org/timezoneJSON' +
- '?lat=38.301733840000004' +
- '&lng=-77.45869621' +
- '&username=fred' +
- '&callback=?';
- jqhxr = $.getJSON(api_url);
+ var api_url = 'http://api.geonames.org/timezoneJSON' +
+ '?lat=38.301733840000004' +
+ '&lng=-77.45869621' +
+ '&username=fred' +
+ '&callback=?';
+ jqhxr = $.getJSON(api_url);
The string ``callback=?`` above in the ``url`` param to the JQuery ``getJSON``
function indicates to jQuery that the query should be made as a JSONP request;
@@ -403,14 +403,14 @@ callable that uses a renderer, assign the ``status`` attribute to the
``response`` attribute of the request before returning a result:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(name='gone', renderer='templates/gone.pt')
- def myview(request):
- request.response.status = '404 Not Found'
- return {'URL':request.URL}
+ @view_config(name='gone', renderer='templates/gone.pt')
+ def myview(request):
+ request.response.status = '404 Not Found'
+ return {'URL':request.URL}
Note that mutations of ``request.response`` in views which return a Response
object directly will have no effect unless the response object returned *is*
@@ -419,23 +419,23 @@ object directly will have no effect unless the response object returned *is*
different Response object is returned.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- def view(request):
- request.response.set_cookie('abc', '123') # this has no effect
- return Response('OK') # because we're returning a different response
+ def view(request):
+ request.response.set_cookie('abc', '123') # this has no effect
+ return Response('OK') # because we're returning a different response
If you mutate ``request.response`` and you'd like the mutations to have an
effect, you must return ``request.response``:
.. code-block:: python
- :linenos:
+ :linenos:
- def view(request):
- request.response.set_cookie('abc', '123')
- return request.response
+ def view(request):
+ request.response.set_cookie('abc', '123')
+ return request.response
For more information on attributes of the request, see the API documentation in
:ref:`request_module`. For more information on the API of
@@ -459,7 +459,7 @@ For example, to add a renderer which renders views which have a
.. code-block:: python
- config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')
+ config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')
The first argument is the renderer name. The second argument is a reference
to an implementation of a :term:`renderer factory` or a :term:`dotted Python
@@ -482,24 +482,24 @@ creating an object that conforms to the :class:`pyramid.interfaces.IRenderer`
interface. A typical class that follows this setup is as follows:
.. code-block:: python
- :linenos:
-
- class RendererFactory:
- def __init__(self, info):
- """ Constructor: info will be an object having the
- following attributes: name (the renderer name), package
- (the package that was 'current' at the time the
- renderer was registered), type (the renderer type
- name), registry (the current application registry) and
- settings (the deployment settings dictionary). """
-
- def __call__(self, value, system):
- """ Call the renderer implementation with the value
- and the system value passed in as arguments and return
- the result (a string or unicode object). The value is
- the return value of a view. The system value is a
- dictionary containing available system values
- (e.g., view, context, and request). """
+ :linenos:
+
+ class RendererFactory:
+ def __init__(self, info):
+ """ Constructor: info will be an object having the
+ following attributes: name (the renderer name), package
+ (the package that was 'current' at the time the
+ renderer was registered), type (the renderer type
+ name), registry (the current application registry) and
+ settings (the deployment settings dictionary). """
+
+ def __call__(self, value, system):
+ """ Call the renderer implementation with the value
+ and the system value passed in as arguments and return
+ the result (a string or unicode object). The value is
+ the return value of a view. The system value is a
+ dictionary containing available system values
+ (e.g., view, context, and request). """
The formal interface definition of the ``info`` object passed to a renderer
factory constructor is available as :class:`pyramid.interfaces.IRendererInfo`.
@@ -532,7 +532,7 @@ instance of :meth:`pyramid.config.Configurator`:
.. code-block:: python
- config.add_renderer(name='amf', factory='my.package.MyAMFRenderer')
+ config.add_renderer(name='amf', factory='my.package.MyAMFRenderer')
Adding the above code to your application startup configuration will
allow you to use the ``my.package.MyAMFRenderer`` renderer factory
@@ -541,13 +541,13 @@ renderer by specifying ``amf`` in the ``renderer`` attribute of a
:term:`view configuration`:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='amf')
- def myview(request):
- return {'Hello':'world'}
+ @view_config(renderer='amf')
+ def myview(request):
+ return {'Hello':'world'}
At startup time, when a :term:`view configuration` is encountered which has a
``name`` attribute that does not contain a dot, the full ``name`` value is used
@@ -561,7 +561,7 @@ which expects to be passed a filesystem path:
.. code-block:: python
- config.add_renderer(name='.jinja2', factory='my.package.MyJinja2Renderer')
+ config.add_renderer(name='.jinja2', factory='my.package.MyJinja2Renderer')
Adding the above code to your application startup will allow you to use the
``my.package.MyJinja2Renderer`` renderer factory implementation in view
@@ -569,13 +569,13 @@ configurations by referring to any ``renderer`` which *ends in* ``.jinja2`` in
the ``renderer`` attribute of a :term:`view configuration`:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='templates/mytemplate.jinja2')
- def myview(request):
- return {'Hello':'world'}
+ @view_config(renderer='templates/mytemplate.jinja2')
+ def myview(request):
+ return {'Hello':'world'}
When a :term:`view configuration` is encountered at startup time which has a
``name`` attribute that does contain a dot, the value of the name attribute is
@@ -597,7 +597,7 @@ attribute to the renderer tag:
.. code-block:: python
- config.add_renderer(None, 'mypackage.json_renderer_factory')
+ config.add_renderer(None, 'mypackage.json_renderer_factory')
.. index::
pair: renderer; changing
@@ -614,8 +614,8 @@ renderer to specify a new renderer, you could do the following:
.. code-block:: python
- json_renderer = pyramid.renderers.JSON()
- config.add_renderer('json', json_renderer)
+ json_renderer = pyramid.renderers.JSON()
+ config.add_renderer('json', json_renderer)
After doing this, any views registered with the ``json`` renderer will use the
new renderer.
@@ -643,23 +643,23 @@ sets an ``override_renderer`` attribute on the request itself, which in turn is
the *name* of a registered renderer. For example:
.. code-block:: python
- :linenos:
-
- from pyramid.events import subscriber
- from pyramid.events import NewRequest
-
- @subscriber(NewRequest)
- def set_xmlrpc_params(event):
- request = event.request
- if (request.content_type == 'text/xml'
- and request.method == 'POST'
- and not 'soapaction' in request.headers
- and not 'x-pyramid-avoid-xmlrpc' in request.headers):
- params, method = parse_xmlrpc_request(request)
- request.xmlrpc_params, request.xmlrpc_method = params, method
- request.is_xmlrpc = True
- request.override_renderer = 'xmlrpc'
- return True
+ :linenos:
+
+ from pyramid.events import subscriber
+ from pyramid.events import NewRequest
+
+ @subscriber(NewRequest)
+ def set_xmlrpc_params(event):
+ request = event.request
+ if (request.content_type == 'text/xml'
+ and request.method == 'POST'
+ and not 'soapaction' in request.headers
+ and not 'x-pyramid-avoid-xmlrpc' in request.headers):
+ params, method = parse_xmlrpc_request(request)
+ request.xmlrpc_params, request.xmlrpc_method = params, method
+ request.is_xmlrpc = True
+ request.override_renderer = 'xmlrpc'
+ return True
The result of such a subscriber will be to replace any existing static renderer
configured by the developer with a (notional, nonexistent) XML-RPC renderer, if
diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst
index 92139c0ff..6b79d575f 100644
--- a/docs/narr/resources.rst
+++ b/docs/narr/resources.rst
@@ -92,9 +92,9 @@ named ``'b'``, and ``'b'`` has a single child named ``'c'``, which has no
children. It is therefore possible to access the ``'c'`` leaf resource like so:
.. code-block:: python
- :linenos:
+ :linenos:
- root['a']['b']['c']
+ root['a']['b']['c']
If you returned the above ``root`` object from a :term:`root factory`, the path
``/a/b/c`` would find the ``'c'`` object in the resource tree as the result of
@@ -133,11 +133,11 @@ The ``__parent__`` of the root resource should be ``None`` and its ``__name__``
should be the empty string. For instance:
.. code-block:: python
- :linenos:
+ :linenos:
- class MyRootResource(object):
- __name__ = ''
- __parent__ = None
+ class MyRootResource(object):
+ __name__ = ''
+ __parent__ = None
A resource returned from the root resource's ``__getitem__`` method should have
a ``__parent__`` attribute that is a reference to the root resource, and its
@@ -222,9 +222,9 @@ The simplest call to :meth:`~pyramid.request.Request.resource_url` looks like
this:
.. code-block:: python
- :linenos:
+ :linenos:
- url = request.resource_url(resource)
+ url = request.resource_url(resource)
The ``request`` in the above example is an instance of a :app:`Pyramid`
:term:`request` object.
@@ -246,9 +246,9 @@ You can also pass extra elements to
:meth:`~pyramid.request.Request.resource_url`:
.. code-block:: python
- :linenos:
+ :linenos:
- url = request.resource_url(resource, 'foo', 'bar')
+ url = request.resource_url(resource, 'foo', 'bar')
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was ``example.com``,
@@ -261,9 +261,9 @@ elements are passed.
You can also pass a query string:
.. code-block:: python
- :linenos:
+ :linenos:
- url = request.resource_url(resource, query={'a':'1'})
+ url = request.resource_url(resource, query={'a':'1'})
If the resource referred to as ``resource`` in the above example was the root
resource, and the host that was used to contact the server was ``example.com``,
@@ -320,11 +320,11 @@ representing a URL. If it cannot override the default, it should return
Here's an example ``__resource_url__`` method.
.. code-block:: python
- :linenos:
+ :linenos:
- class Resource(object):
- def __resource_url__(self, request, info):
- return info['app_url'] + info['virtual_path']
+ class Resource(object):
+ def __resource_url__(self, request, info):
+ return info['app_url'] + info['virtual_path']
The above example actually just generates and returns the default URL, which
would have been what was generated by the default ``resource_url`` machinery,
@@ -347,10 +347,10 @@ the absolute physical path of the resource object based on its position in the
resource tree. Each segment of the path is separated with a slash character.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.traversal import resource_path
- url = resource_path(resource)
+ from pyramid.traversal import resource_path
+ url = resource_path(resource)
If ``resource`` in the example above was accessible in the tree as
``root['a']['b']``, the above example would generate the string ``/a/b``.
@@ -359,10 +359,10 @@ Any positional arguments passed in to :func:`~pyramid.traversal.resource_path`
will be appended as path segments to the end of the resource path.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.traversal import resource_path
- url = resource_path(resource, 'foo', 'bar')
+ from pyramid.traversal import resource_path
+ url = resource_path(resource, 'foo', 'bar')
If ``resource`` in the example above was accessible in the tree as
``root['a']['b']``, the above example would generate the string
@@ -387,20 +387,20 @@ You can resolve an absolute path by passing a string prefixed with a ``/`` as
the ``path`` argument:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.traversal import find_resource
- url = find_resource(anyresource, '/path')
+ from pyramid.traversal import find_resource
+ url = find_resource(anyresource, '/path')
Or you can resolve a path relative to the resource that you pass in to
:func:`pyramid.traversal.find_resource` by passing a string that isn't prefixed
by ``/``:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.traversal import find_resource
- url = find_resource(anyresource, 'path')
+ from pyramid.traversal import find_resource
+ url = find_resource(anyresource, 'path')
Often the paths you pass to :func:`~pyramid.traversal.find_resource` are
generated by the :func:`~pyramid.traversal.resource_path` API. These APIs are
@@ -427,22 +427,22 @@ passed into it, then each parent of the resource in order. For example, if the
resource tree is composed like so:
.. code-block:: python
- :linenos:
+ :linenos:
- class Thing(object): pass
+ class Thing(object): pass
- thing1 = Thing()
- thing2 = Thing()
- thing2.__parent__ = thing1
+ thing1 = Thing()
+ thing2 = Thing()
+ thing2.__parent__ = thing1
Calling ``lineage(thing2)`` will return a generator. When we turn it into a
list, we will get:
.. code-block:: python
- :linenos:
+ :linenos:
- list(lineage(thing2))
- [ <Thing object at thing2>, <Thing object at thing1> ]
+ list(lineage(thing2))
+ [ <Thing object at thing2>, <Thing object at thing1> ]
The generator returned by :func:`~pyramid.location.lineage` first returns
unconditionally the resource that was passed into it. Then, if the resource
@@ -464,13 +464,13 @@ is in the :term:`lineage` of another resource.
For example, if the resource tree is:
.. code-block:: python
- :linenos:
+ :linenos:
- class Thing(object): pass
+ class Thing(object): pass
- a = Thing()
- b = Thing()
- b.__parent__ = a
+ a = Thing()
+ b = Thing()
+ b.__parent__ = a
Calling ``inside(b, a)`` will return ``True``, because ``b`` has a lineage that
includes ``a``. However, calling ``inside(a, b)`` will return ``False``
@@ -498,13 +498,13 @@ you want to find the root.
For example, if the resource tree is:
.. code-block:: python
- :linenos:
+ :linenos:
- class Thing(object): pass
+ class Thing(object): pass
- a = Thing()
- b = Thing()
- b.__parent__ = a
+ a = Thing()
+ b = Thing()
+ b.__parent__ = a
Calling ``find_root(b)`` will return ``a``.
@@ -538,22 +538,22 @@ For example, here's some code which describes a blog entry which also declares
that the blog entry implements an :term:`interface`.
.. code-block:: python
- :linenos:
+ :linenos:
- import datetime
- from zope.interface import implementer
- from zope.interface import Interface
+ import datetime
+ from zope.interface import implementer
+ from zope.interface import Interface
- class IBlogEntry(Interface):
- pass
+ class IBlogEntry(Interface):
+ pass
- @implementer(IBlogEntry)
- class BlogEntry(object):
- def __init__(self, title, body, author):
- self.title = title
- self.body = body
- self.author = author
- self.created = datetime.datetime.now()
+ @implementer(IBlogEntry)
+ class BlogEntry(object):
+ def __init__(self, title, body, author):
+ self.title = title
+ self.body = body
+ self.author = author
+ self.created = datetime.datetime.now()
This resource consists of two things: the class which defines the resource
constructor as the class ``BlogEntry``, and an :term:`interface` attached to
@@ -575,24 +575,24 @@ However, you can also just say that a single object provides the interface. To
do so, use the :func:`zope.interface.directlyProvides` function:
.. code-block:: python
- :linenos:
+ :linenos:
- import datetime
- from zope.interface import directlyProvides
- from zope.interface import Interface
+ import datetime
+ from zope.interface import directlyProvides
+ from zope.interface import Interface
- class IBlogEntry(Interface):
- pass
+ class IBlogEntry(Interface):
+ pass
- class BlogEntry(object):
- def __init__(self, title, body, author):
- self.title = title
- self.body = body
- self.author = author
- self.created = datetime.datetime.now()
+ class BlogEntry(object):
+ def __init__(self, title, body, author):
+ self.title = title
+ self.body = body
+ self.author = author
+ self.created = datetime.datetime.now()
- entry = BlogEntry('title', 'body', 'author')
- directlyProvides(entry, IBlogEntry)
+ entry = BlogEntry('title', 'body', 'author')
+ directlyProvides(entry, IBlogEntry)
:func:`zope.interface.directlyProvides` will replace any existing interface
that was previously provided by an instance. If a resource object already has
@@ -600,29 +600,29 @@ instance-level interface declarations that you don't want to replace, use the
:func:`zope.interface.alsoProvides` function:
.. code-block:: python
- :linenos:
+ :linenos:
- import datetime
- from zope.interface import alsoProvides
- from zope.interface import directlyProvides
- from zope.interface import Interface
+ import datetime
+ from zope.interface import alsoProvides
+ from zope.interface import directlyProvides
+ from zope.interface import Interface
- class IBlogEntry1(Interface):
- pass
+ class IBlogEntry1(Interface):
+ pass
- class IBlogEntry2(Interface):
- pass
+ class IBlogEntry2(Interface):
+ pass
- class BlogEntry(object):
- def __init__(self, title, body, author):
- self.title = title
- self.body = body
- self.author = author
- self.created = datetime.datetime.now()
+ class BlogEntry(object):
+ def __init__(self, title, body, author):
+ self.title = title
+ self.body = body
+ self.author = author
+ self.created = datetime.datetime.now()
- entry = BlogEntry('title', 'body', 'author')
- directlyProvides(entry, IBlogEntry1)
- alsoProvides(entry, IBlogEntry2)
+ entry = BlogEntry('title', 'body', 'author')
+ directlyProvides(entry, IBlogEntry1)
+ alsoProvides(entry, IBlogEntry2)
:func:`zope.interface.alsoProvides` will augment the set of interfaces directly
provided by an instance instead of overwriting them like
@@ -643,14 +643,14 @@ is of a particular Python class, or which implements some :term:`interface`.
For example, if your resource tree is composed as follows:
.. code-block:: python
- :linenos:
+ :linenos:
- class Thing1(object): pass
- class Thing2(object): pass
+ class Thing1(object): pass
+ class Thing2(object): pass
- a = Thing1()
- b = Thing2()
- b.__parent__ = a
+ a = Thing1()
+ b = Thing2()
+ b.__parent__ = a
Calling ``find_interface(a, Thing1)`` will return the ``a`` resource because
``a`` is of class ``Thing1`` (the resource passed as the first argument is
diff --git a/docs/narr/scaffolding.rst b/docs/narr/scaffolding.rst
index b962bc274..083d831cc 100644
--- a/docs/narr/scaffolding.rst
+++ b/docs/narr/scaffolding.rst
@@ -37,15 +37,15 @@ distribution's package directory, and create a file within that directory named
``__init__.py`` with something like the following:
.. code-block:: python
- :linenos:
+ :linenos:
- # CoolExtension/coolextension/scaffolds/__init__.py
+ # CoolExtension/coolextension/scaffolds/__init__.py
- from pyramid.scaffolds import PyramidTemplate
+ from pyramid.scaffolds import PyramidTemplate
- class CoolExtensionTemplate(PyramidTemplate):
- _template_dir = 'coolextension_scaffold'
- summary = 'My cool extension'
+ class CoolExtensionTemplate(PyramidTemplate):
+ _template_dir = 'coolextension_scaffold'
+ summary = 'My cool extension'
Once this is done, within the ``scaffolds`` directory, create a template
directory. Our example used a template directory named
@@ -85,19 +85,19 @@ After you've created the template directory, add the following to the
.. code-block:: ini
- [pyramid.scaffold]
- coolextension=coolextension.scaffolds:CoolExtensionTemplate
+ [pyramid.scaffold]
+ coolextension=coolextension.scaffolds:CoolExtensionTemplate
For example:
.. code-block:: python
def setup(
- ...,
- entry_points = """\
+ #...,
+ entry_points = """\
[pyramid.scaffold]
coolextension=coolextension.scaffolds:CoolExtensionTemplate
- """
+ """
)
Run your distribution's ``setup.py develop`` or ``setup.py install`` command.
@@ -120,25 +120,25 @@ want to have extension scaffolds that can work across Pyramid 1.0.X, 1.1.X,
defining your scaffold template:
.. code-block:: python
- :linenos:
-
- try: # pyramid 1.0.X
- # "pyramid.paster.paste_script..." doesn't exist past 1.0.X
- from pyramid.paster import paste_script_template_renderer
- from pyramid.paster import PyramidTemplate
- except ImportError:
- try: # pyramid 1.1.X, 1.2.X
- # trying to import "paste_script_template_renderer" fails on 1.3.X
- from pyramid.scaffolds import paste_script_template_renderer
- from pyramid.scaffolds import PyramidTemplate
- except ImportError: # pyramid >=1.3a2
- paste_script_template_renderer = None
- from pyramid.scaffolds import PyramidTemplate
-
- class CoolExtensionTemplate(PyramidTemplate):
- _template_dir = 'coolextension_scaffold'
- summary = 'My cool extension'
- template_renderer = staticmethod(paste_script_template_renderer)
+ :linenos:
+
+ try: # pyramid 1.0.X
+ # "pyramid.paster.paste_script..." doesn't exist past 1.0.X
+ from pyramid.paster import paste_script_template_renderer
+ from pyramid.paster import PyramidTemplate
+ except ImportError:
+ try: # pyramid 1.1.X, 1.2.X
+ # trying to import "paste_script_template_renderer" fails on 1.3.X
+ from pyramid.scaffolds import paste_script_template_renderer
+ from pyramid.scaffolds import PyramidTemplate
+ except ImportError: # pyramid >=1.3a2
+ paste_script_template_renderer = None
+ from pyramid.scaffolds import PyramidTemplate
+
+ class CoolExtensionTemplate(PyramidTemplate):
+ _template_dir = 'coolextension_scaffold'
+ summary = 'My cool extension'
+ template_renderer = staticmethod(paste_script_template_renderer)
And then in the setup.py of the package that contains your scaffold, define
the template as a target of both ``paste.paster_create_template`` (for
@@ -160,13 +160,13 @@ If you want to support Pyramid 1.3 only, it's much cleaner, and the API is
stable:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.scaffolds import PyramidTemplate
+ from pyramid.scaffolds import PyramidTemplate
- class CoolExtensionTemplate(PyramidTemplate):
- _template_dir = 'coolextension_scaffold'
- summary = 'My cool_extension'
+ class CoolExtensionTemplate(PyramidTemplate):
+ _template_dir = 'coolextension_scaffold'
+ summary = 'My cool_extension'
You only need to specify a ``paste.paster_create_template`` entry point target
in your ``setup.py`` if you want your scaffold to be consumable by users of
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 0265152fa..5bccd6d52 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -88,16 +88,16 @@ application setup to specify the authentication policy.
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
- from pyramid.authentication import AuthTktAuthenticationPolicy
- from pyramid.authorization import ACLAuthorizationPolicy
- authn_policy = AuthTktAuthenticationPolicy('seekrit', hashalg='sha512')
- authz_policy = ACLAuthorizationPolicy()
- config = Configurator()
- config.set_authentication_policy(authn_policy)
- config.set_authorization_policy(authz_policy)
+ from pyramid.config import Configurator
+ from pyramid.authentication import AuthTktAuthenticationPolicy
+ from pyramid.authorization import ACLAuthorizationPolicy
+ authn_policy = AuthTktAuthenticationPolicy('seekrit', hashalg='sha512')
+ authz_policy = ACLAuthorizationPolicy()
+ config = Configurator()
+ config.set_authentication_policy(authn_policy)
+ config.set_authorization_policy(authz_policy)
.. note:: The ``authentication_policy`` and ``authorization_policy`` arguments
may also be passed to their respective methods mentioned above as
@@ -141,28 +141,28 @@ For example, the following view declaration protects the view named
``add`` permission using the :meth:`pyramid.config.Configurator.add_view` API:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_view('mypackage.views.blog_entry_add_view',
- name='add_entry.html',
- context='mypackage.resources.Blog',
- permission='add')
+ config.add_view('mypackage.views.blog_entry_add_view',
+ name='add_entry.html',
+ context='mypackage.resources.Blog',
+ permission='add')
The equivalent view registration including the ``add`` permission name may be
performed via the ``@view_config`` decorator:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from resources import Blog
+ from pyramid.view import view_config
+ from resources import Blog
- @view_config(context=Blog, name='add_entry.html', permission='add')
- def blog_entry_add_view(request):
- """ Add blog entry code goes here """
- pass
+ @view_config(context=Blog, name='add_entry.html', permission='add')
+ def blog_entry_add_view(request):
+ """ Add blog entry code goes here """
+ pass
As a result of any of these various view configuration statements, if an
authorization policy is in place when the view callable is found during normal
@@ -231,37 +231,37 @@ just need type-level security.
For example, an ACL might be attached to the resource for a blog via its class:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
- class Blog(object):
- __acl__ = [
- (Allow, Everyone, 'view'),
- (Allow, 'group:editors', 'add'),
- (Allow, 'group:editors', 'edit'),
- ]
+ class Blog(object):
+ __acl__ = [
+ (Allow, Everyone, 'view'),
+ (Allow, 'group:editors', 'add'),
+ (Allow, 'group:editors', 'edit'),
+ ]
Or, if your resources are persistent, an ACL might be specified via the
``__acl__`` attribute of an *instance* of a resource:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
- class Blog(object):
- pass
+ class Blog(object):
+ pass
- blog = Blog()
+ blog = Blog()
- blog.__acl__ = [
- (Allow, Everyone, 'view'),
- (Allow, 'group:editors', 'add'),
- (Allow, 'group:editors', 'edit'),
- ]
+ blog.__acl__ = [
+ (Allow, Everyone, 'view'),
+ (Allow, 'group:editors', 'add'),
+ (Allow, 'group:editors', 'edit'),
+ ]
Whether an ACL is attached to a resource's class or an instance of the resource
itself, the effect is the same. It is useful to decorate individual resource
@@ -274,21 +274,21 @@ resource. This may allow the ACL to dynamically generate rules based on
properties of the instance.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
- class Blog(object):
- def __acl__(self):
- return [
- (Allow, Everyone, 'view'),
- (Allow, self.owner, 'edit'),
- (Allow, 'group:editors', 'edit'),
- ]
+ class Blog(object):
+ def __acl__(self):
+ return [
+ (Allow, Everyone, 'view'),
+ (Allow, self.owner, 'edit'),
+ (Allow, 'group:editors', 'edit'),
+ ]
- def __init__(self, owner):
- self.owner = owner
+ def __init__(self, owner):
+ self.owner = owner
.. warning::
@@ -308,16 +308,16 @@ Elements of an ACL
Here's an example ACL:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
- __acl__ = [
- (Allow, Everyone, 'view'),
- (Allow, 'group:editors', 'add'),
- (Allow, 'group:editors', 'edit'),
- ]
+ __acl__ = [
+ (Allow, Everyone, 'view'),
+ (Allow, 'group:editors', 'add'),
+ (Allow, 'group:editors', 'edit'),
+ ]
The example ACL indicates that the :data:`pyramid.security.Everyone`
principal—a special system-defined principal indicating, literally, everyone—is
@@ -342,32 +342,32 @@ Each ACE in an ACL is processed by an authorization policy *in the order
dictated by the ACL*. So if you have an ACL like this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import Deny
- from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Deny
+ from pyramid.security import Everyone
- __acl__ = [
- (Allow, Everyone, 'view'),
- (Deny, Everyone, 'view'),
- ]
+ __acl__ = [
+ (Allow, Everyone, 'view'),
+ (Deny, Everyone, 'view'),
+ ]
The default authorization policy will *allow* everyone the view permission,
even though later in the ACL you have an ACE that denies everyone the view
permission. On the other hand, if you have an ACL like this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Everyone
- from pyramid.security import Allow
- from pyramid.security import Deny
+ from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Deny
- __acl__ = [
- (Deny, Everyone, 'view'),
- (Allow, Everyone, 'view'),
- ]
+ __acl__ = [
+ (Deny, Everyone, 'view'),
+ (Allow, Everyone, 'view'),
+ ]
The authorization policy will deny everyone the view permission, even though
later in the ACL, there is an ACE that allows everyone.
@@ -378,15 +378,15 @@ a number of different permission grants to a single ``group:editors`` group, we
can collapse this into a single ACE, as below.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import Everyone
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
- __acl__ = [
- (Allow, Everyone, 'view'),
- (Allow, 'group:editors', ('add', 'edit')),
- ]
+ __acl__ = [
+ (Allow, Everyone, 'view'),
+ (Allow, 'group:editors', ('add', 'edit')),
+ ]
.. index::
@@ -449,21 +449,21 @@ particular resource, despite what inherited ACLs may say when the default
authorization policy is in effect, might look like so:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import Allow
- from pyramid.security import DENY_ALL
+ from pyramid.security import Allow
+ from pyramid.security import DENY_ALL
- __acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ]
+ __acl__ = [ (Allow, 'fred', 'view'), DENY_ALL ]
Under the hood, the :data:`pyramid.security.DENY_ALL` ACE equals the
following:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.security import ALL_PERMISSIONS
- __acl__ = [ (Deny, Everyone, ALL_PERMISSIONS) ]
+ from pyramid.security import ALL_PERMISSIONS
+ __acl__ = [ (Deny, Everyone, ALL_PERMISSIONS) ]
.. index::
single: ACL inheritance
@@ -484,11 +484,11 @@ means two things: the root object in the resource tree must have a ``__name__``
attribute and a ``__parent__`` attribute.
.. code-block:: python
- :linenos:
+ :linenos:
- class Blog(object):
- __name__ = ''
- __parent__ = None
+ class Blog(object):
+ __name__ = ''
+ __parent__ = None
An object with a ``__parent__`` attribute and a ``__name__`` attribute is said
to be *location-aware*. Location-aware objects define a ``__parent__``
@@ -531,7 +531,7 @@ example:
.. code-block:: text
- $ PYRAMID_DEBUG_AUTHORIZATION=1 $VENV/bin/pserve myproject.ini
+ PYRAMID_DEBUG_AUTHORIZATION=1 $VENV/bin/pserve myproject.ini
When any authorization takes place during a top-level view rendering, a message
will be logged to the console (to stderr) about what ACE in which ACL permitted
@@ -542,11 +542,11 @@ the ``pyramid.debug_authorization`` key to ``true`` within the application's
configuration section, e.g.:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyProject
- pyramid.debug_authorization = true
+ [app:main]
+ use = egg:MyProject
+ pyramid.debug_authorization = true
With this debug flag turned on, the response sent to the browser will also
contain security debugging information in its body.
@@ -597,23 +597,23 @@ use that :term:`userid` to augment the ``effective_principals`` with
information about groups and other state for that user.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.authentication import AuthTktAuthenticationPolicy
+ from pyramid.authentication import AuthTktAuthenticationPolicy
- class MyAuthenticationPolicy(AuthTktAuthenticationPolicy):
- def authenticated_userid(self, request):
- userid = self.unauthenticated_userid(request)
- if userid:
- if request.verify_userid_is_still_valid(userid):
- return userid
+ class MyAuthenticationPolicy(AuthTktAuthenticationPolicy):
+ def authenticated_userid(self, request):
+ userid = self.unauthenticated_userid(request)
+ if userid:
+ if request.verify_userid_is_still_valid(userid):
+ return userid
- def effective_principals(self, request):
- principals = [Everyone]
- userid = self.authenticated_userid(request)
- if userid:
- principals += [Authenticated, str(userid)]
- return principals
+ def effective_principals(self, request):
+ principals = [Everyone]
+ userid = self.authenticated_userid(request)
+ if userid:
+ principals += [Authenticated, str(userid)]
+ return principals
In most instances ``authenticated_userid`` and ``effective_principals`` are
application-specific, whereas ``unauthenticated_userid``, ``remember``, and
@@ -635,59 +635,54 @@ vertical" of how your users authenticate. Doing so is a matter of creating an
instance of something that implements the following interface:
.. code-block:: python
- :linenos:
-
- class IAuthenticationPolicy(object):
- """ An object representing a Pyramid authentication policy. """
-
- def authenticated_userid(self, request):
- """ Return the authenticated :term:`userid` or ``None`` if
- no authenticated userid can be found. This method of the
- policy should ensure that a record exists in whatever
- persistent store is used related to the user (the user
- should not have been deleted); if a record associated with
- the current id does not exist in a persistent store, it
- should return ``None``.
-
- """
-
- def unauthenticated_userid(self, request):
- """ Return the *unauthenticated* userid. This method
- performs the same duty as ``authenticated_userid`` but is
- permitted to return the userid based only on data present
- in the request; it needn't (and shouldn't) check any
- persistent store to ensure that the user record related to
- the request userid exists.
-
- This method is intended primarily a helper to assist the
- ``authenticated_userid`` method in pulling credentials out
- of the request data, abstracting away the specific headers,
- query strings, etc that are used to authenticate the request.
-
- """
-
- def effective_principals(self, request):
- """ Return a sequence representing the effective principals
- typically including the :term:`userid` and any groups belonged
- to by the current user, always including 'system' groups such
- as ``pyramid.security.Everyone`` and
- ``pyramid.security.Authenticated``.
+ :linenos:
- """
+ class IAuthenticationPolicy(object):
+ """ An object representing a Pyramid authentication policy. """
+
+ def authenticated_userid(self, request):
+ """ Return the authenticated :term:`userid` or ``None`` if
+ no authenticated userid can be found. This method of the
+ policy should ensure that a record exists in whatever
+ persistent store is used related to the user (the user
+ should not have been deleted); if a record associated with
+ the current id does not exist in a persistent store, it
+ should return ``None``.
+ """
- def remember(self, request, userid, **kw):
- """ Return a set of headers suitable for 'remembering' the
- :term:`userid` named ``userid`` when set in a response. An
- individual authentication policy and its consumers can
- decide on the composition and meaning of **kw.
+ def unauthenticated_userid(self, request):
+ """ Return the *unauthenticated* userid. This method
+ performs the same duty as ``authenticated_userid`` but is
+ permitted to return the userid based only on data present
+ in the request; it needn't (and shouldn't) check any
+ persistent store to ensure that the user record related to
+ the request userid exists.
+
+ This method is intended primarily a helper to assist the
+ ``authenticated_userid`` method in pulling credentials out
+ of the request data, abstracting away the specific headers,
+ query strings, etc that are used to authenticate the request.
+ """
- """
+ def effective_principals(self, request):
+ """ Return a sequence representing the effective principals
+ typically including the :term:`userid` and any groups belonged
+ to by the current user, always including 'system' groups such
+ as ``pyramid.security.Everyone`` and
+ ``pyramid.security.Authenticated``.
+ """
- def forget(self, request):
- """ Return a set of headers suitable for 'forgetting' the
- current user on subsequent requests.
+ def remember(self, request, userid, **kw):
+ """ Return a set of headers suitable for 'remembering' the
+ :term:`userid` named ``userid`` when set in a response. An
+ individual authentication policy and its consumers can
+ decide on the composition and meaning of **kw.
+ """
- """
+ def forget(self, request):
+ """ Return a set of headers suitable for 'forgetting' the
+ current user on subsequent requests.
+ """
After you do so, you can pass an instance of such a class into the
:class:`~pyramid.config.Configurator.set_authentication_policy` method at
@@ -798,10 +793,10 @@ For example:
.. code-block:: python
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- config = Configurator()
- config.set_csrf_storage_policy(MyCustomCSRFPolicy())
+ config = Configurator()
+ config.set_csrf_storage_policy(MyCustomCSRFPolicy())
.. index::
single: csrf.get_csrf_token
@@ -814,8 +809,8 @@ To get the current CSRF token, use the
.. code-block:: python
- from pyramid.csrf import get_csrf_token
- token = get_csrf_token(request)
+ 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()``
@@ -874,8 +869,8 @@ the user, and returns the token.
.. code-block:: python
- from pyramid.csrf import new_csrf_token
- token = new_csrf_token(request)
+ from pyramid.csrf import new_csrf_token
+ token = new_csrf_token(request)
.. note::
@@ -897,13 +892,13 @@ named ``X-CSRF-Token``.
.. code-block:: python
- from pyramid.csrf import check_csrf_token
+ from pyramid.csrf import check_csrf_token
- def myview(request):
- # Require CSRF Token
- check_csrf_token(request)
+ def myview(request):
+ # Require CSRF Token
+ check_csrf_token(request)
- # ...
+ # ...
.. _auto_csrf_checking:
@@ -920,10 +915,10 @@ For example:
.. code-block:: python
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- config = Configurator()
- config.set_default_csrf_options(require_csrf=True)
+ 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
@@ -931,9 +926,9 @@ 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):
- # ...
+ @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,
@@ -968,9 +963,9 @@ include ``check_csrf=True`` as a view predicate. See
.. code-block:: python
- @view_config(request_method='POST', check_csrf=True, ...)
- def myview(request):
- ...
+ @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
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index c0354841c..6c88dcec5 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -45,14 +45,14 @@ You can configure this session factory in your :app:`Pyramid` application by
using the :meth:`pyramid.config.Configurator.set_session_factory` method.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.session import SignedCookieSessionFactory
- my_session_factory = SignedCookieSessionFactory('itsaseekreet')
+ from pyramid.session import SignedCookieSessionFactory
+ my_session_factory = SignedCookieSessionFactory('itsaseekreet')
- from pyramid.config import Configurator
- config = Configurator()
- config.set_session_factory(my_session_factory)
+ from pyramid.config import Configurator
+ config = Configurator()
+ config.set_session_factory(my_session_factory)
.. warning::
@@ -81,19 +81,19 @@ session objects provided by the session factory via the ``session`` attribute
of any :term:`request` object. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- def myview(request):
- session = request.session
- if 'abc' in session:
- session['fred'] = 'yes'
- session['abc'] = '123'
- if 'fred' in session:
- return Response('Fred was in the session')
- else:
- return Response('Fred was not in the session')
+ def myview(request):
+ session = request.session
+ if 'abc' in session:
+ session['fred'] = 'yes'
+ session['abc'] = '123'
+ if 'fred' in session:
+ return Response('Fred was in the session')
+ else:
+ return Response('Fred was not in the session')
The first time this view is invoked produces ``Fred was not in the session``.
Subsequent invocations produce ``Fred was in the session``, assuming of course
@@ -223,7 +223,7 @@ method:
.. code-block:: python
- request.session.flash('mymessage')
+ request.session.flash('mymessage')
The ``flash()`` method appends a message to a flash queue, creating the queue
if necessary.
@@ -246,7 +246,7 @@ represents the default flash message queue.
.. code-block:: python
- request.session.flash(msg, 'myappsqueue')
+ request.session.flash(msg, 'myappsqueue')
The ``allow_duplicate`` argument defaults to ``True``. If this is ``False``,
and you attempt to add a message value which is already present in the queue,
diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst
index 5e7c7c871..90792c0ff 100644
--- a/docs/narr/startup.rst
+++ b/docs/narr/startup.rst
@@ -8,7 +8,7 @@ you'll see something much like this show up on the console:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini
+ $VENV/bin/pserve development.ini
Starting server in PID 16305.
Serving on http://localhost:6543
Serving on http://localhost:6543
diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst
index b4deb42f2..9094c7d83 100644
--- a/docs/narr/subrequest.rst
+++ b/docs/narr/subrequest.rst
@@ -17,30 +17,30 @@ application.
Here's an example application which uses a subrequest:
.. code-block:: python
- :linenos:
-
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.request import Request
-
- def view_one(request):
- subreq = Request.blank('/view_two')
- response = request.invoke_subrequest(subreq)
- return response
-
- def view_two(request):
- request.response.body = 'This came from view_two'
- return request.response
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_route('one', '/view_one')
- config.add_route('two', '/view_two')
- config.add_view(view_one, route_name='one')
- config.add_view(view_two, route_name='two')
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ :linenos:
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ request.response.body = 'This came from view_two'
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
When ``/view_one`` is visted in a browser, the text printed in the browser pane
will be ``This came from view_two``. The ``view_one`` view used the
@@ -61,30 +61,30 @@ adapter when found and invoked via
object:
.. code-block:: python
- :linenos:
- :emphasize-lines: 11,18
-
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.request import Request
-
- def view_one(request):
- subreq = Request.blank('/view_two')
- response = request.invoke_subrequest(subreq)
- return response
-
- def view_two(request):
- return 'This came from view_two'
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_route('one', '/view_one')
- config.add_route('two', '/view_two')
- config.add_view(view_one, route_name='one')
- config.add_view(view_two, route_name='two', renderer='string')
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ :linenos:
+ :emphasize-lines: 11,18
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ return 'This came from view_two'
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
Even though the ``view_two`` view callable returned a string, it was invoked in
such a way that the ``string`` renderer associated with the view registration
@@ -106,36 +106,36 @@ exception, the exception will be raised to the caller of
:term:`exception view` configured:
.. code-block:: python
- :linenos:
- :emphasize-lines: 11-16
-
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.request import Request
-
- def view_one(request):
- subreq = Request.blank('/view_two')
- response = request.invoke_subrequest(subreq)
- return response
-
- def view_two(request):
- raise ValueError('foo')
-
- def excview(request):
- request.response.body = b'An exception was raised'
- request.response.status_int = 500
- return request.response
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_route('one', '/view_one')
- config.add_route('two', '/view_two')
- config.add_view(view_one, route_name='one')
- config.add_view(view_two, route_name='two', renderer='string')
- config.add_view(excview, context=Exception)
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ :linenos:
+ :emphasize-lines: 11-16
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ raise ValueError('foo')
+
+ def excview(request):
+ request.response.body = b'An exception was raised'
+ request.response.status_int = 500
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(excview, context=Exception)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
When we run the above code and visit ``/view_one`` in a browser, the
``excview`` :term:`exception view` will *not* be executed. Instead, the call
@@ -175,36 +175,36 @@ We can cause the subrequest to be run through the tween stack by passing
:meth:`~pyramid.request.Request.invoke_subrequest`, like this:
.. code-block:: python
- :linenos:
- :emphasize-lines: 7
-
- from wsgiref.simple_server import make_server
- from pyramid.config import Configurator
- from pyramid.request import Request
-
- def view_one(request):
- subreq = Request.blank('/view_two')
- response = request.invoke_subrequest(subreq, use_tweens=True)
- return response
-
- def view_two(request):
- raise ValueError('foo')
-
- def excview(request):
- request.response.body = b'An exception was raised'
- request.response.status_int = 500
- return request.response
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_route('one', '/view_one')
- config.add_route('two', '/view_two')
- config.add_view(view_one, route_name='one')
- config.add_view(view_two, route_name='two', renderer='string')
- config.add_view(excview, context=Exception)
- app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080, app)
- server.serve_forever()
+ :linenos:
+ :emphasize-lines: 7
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq, use_tweens=True)
+ return response
+
+ def view_two(request):
+ raise ValueError('foo')
+
+ def excview(request):
+ request.response.body = b'An exception was raised'
+ request.response.status_int = 500
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(excview, context=Exception)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
In the above case, the call to ``request.invoke_subrequest(subreq)`` will not
raise an exception. Instead, it will retrieve a "500" response from the
@@ -312,20 +312,20 @@ Below is an example usage of
:meth:`pyramid.request.Request.invoke_exception_view`:
.. code-block:: python
- :linenos:
-
- def foo(request):
- try:
- some_func_that_errors()
- return response
- except Exception:
- response = request.invoke_exception_view()
- if response is not None:
- return response
- else:
- # there is no exception view for this exception, simply
- # re-raise and let someone else handle it
- raise
+ :linenos:
+
+ def foo(request):
+ try:
+ some_func_that_errors()
+ return response
+ except Exception:
+ response = request.invoke_exception_view()
+ if response is not None:
+ return response
+ else:
+ # there is no exception view for this exception, simply
+ # re-raise and let someone else handle it
+ raise
Please note that in most cases you do not need to write code like this, and you
may rely on the ``EXCVIEW`` tween to handle this for you.
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 156cb863f..1ccab9d3c 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -31,14 +31,14 @@ application, you can render the template from within the body of a view
callable like so:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render_to_response
+ from pyramid.renderers import render_to_response
- def sample_view(request):
- return render_to_response('templates/foo.pt',
- {'foo':1, 'bar':2},
- request=request)
+ def sample_view(request):
+ return render_to_response('templates/foo.pt',
+ {'foo':1, 'bar':2},
+ request=request)
The ``sample_view`` :term:`view callable` function above returns a
:term:`response` object which contains the body of the ``templates/foo.pt``
@@ -52,20 +52,20 @@ directory containing the file which defines the view configuration. In this
case, this is the directory containing the file that defines the
``sample_view`` function. Although a renderer path is usually just a simple
relative pathname, a path named as a renderer can be absolute, starting with a
-slash on UNIX or a drive letter prefix on Windows. The path can alternatively
+slash on Unix or a drive letter prefix on Windows. The path can alternatively
be an :term:`asset specification` in the form
``some.dotted.package_name:relative/path``. This makes it possible to address
template assets which live in another package. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render_to_response
+ from pyramid.renderers import render_to_response
- def sample_view(request):
- return render_to_response('mypackage:templates/foo.pt',
- {'foo':1, 'bar':2},
- request=request)
+ def sample_view(request):
+ return render_to_response('mypackage:templates/foo.pt',
+ {'foo':1, 'bar':2},
+ request=request)
An asset specification points at a file within a Python *package*. In this
case, it points at a file named ``foo.pt`` within the ``templates`` directory
@@ -99,17 +99,17 @@ manufacture a :term:`response` object directly, and use that string as the body
of the response:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render
- from pyramid.response import Response
+ from pyramid.renderers import render
+ from pyramid.response import Response
- def sample_view(request):
- result = render('mypackage:templates/foo.pt',
- {'foo':1, 'bar':2},
- request=request)
- response = Response(result)
- return response
+ def sample_view(request):
+ result = render('mypackage:templates/foo.pt',
+ {'foo':1, 'bar':2},
+ request=request)
+ response = Response(result)
+ return response
Because :term:`view callable` functions are typically the only code in
:app:`Pyramid` that need to know anything about templates, and because view
@@ -123,16 +123,16 @@ For example, here's an example of using "raw" Mako_ from within a
:app:`Pyramid` :term:`view`:
.. code-block:: python
- :linenos:
+ :linenos:
- from mako.template import Template
- from pyramid.response import Response
+ from mako.template import Template
+ from pyramid.response import Response
- def make_view(request):
- template = Template(filename='/templates/template.mak')
- result = template.render(name=request.params['name'])
- response = Response(result)
- return response
+ def make_view(request):
+ template = Template(filename='/templates/template.mak')
+ result = template.render(name=request.params['name'])
+ response = Response(result)
+ return response
You probably wouldn't use this particular snippet in a project, because it's
easier to use the supported :ref:`Mako bindings
@@ -163,34 +163,34 @@ Here's an example of changing the content-type and status of the response
object returned by :func:`~pyramid.renderers.render_to_response`:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render_to_response
+ from pyramid.renderers import render_to_response
- def sample_view(request):
- response = render_to_response('templates/foo.pt',
- {'foo':1, 'bar':2},
- request=request)
- response.content_type = 'text/plain'
- response.status_int = 204
- return response
+ def sample_view(request):
+ response = render_to_response('templates/foo.pt',
+ {'foo':1, 'bar':2},
+ request=request)
+ response.content_type = 'text/plain'
+ response.status_int = 204
+ return response
Here's an example of manufacturing a response object using the result of
:func:`~pyramid.renderers.render` (a string):
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.renderers import render
- from pyramid.response import Response
+ from pyramid.renderers import render
+ from pyramid.response import Response
- def sample_view(request):
- result = render('mypackage:templates/foo.pt',
- {'foo':1, 'bar':2},
- request=request)
- response = Response(result)
- response.content_type = 'text/plain'
- return response
+ def sample_view(request):
+ result = render('mypackage:templates/foo.pt',
+ {'foo':1, 'bar':2},
+ request=request)
+ response = Response(result)
+ response.content_type = 'text/plain'
+ return response
.. index::
single: templates used as renderers
@@ -284,13 +284,13 @@ Here's an example of using a :class:`~pyramid.view.view_config` decorator to
specify a :term:`view configuration` that names a template renderer:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(renderer='templates/foo.pt')
- def my_view(request):
- return {'foo':1, 'bar':2}
+ @view_config(renderer='templates/foo.pt')
+ def my_view(request):
+ return {'foo':1, 'bar':2}
.. note::
@@ -317,7 +317,7 @@ Similar renderer configuration can be done imperatively. See
See also :ref:`built_in_renderers`.
Although a renderer path is usually just a simple relative pathname, a path
-named as a renderer can be absolute, starting with a slash on UNIX or a drive
+named as a renderer can be absolute, starting with a slash on Unix or a drive
letter prefix on Windows. The path can alternatively be an :term:`asset
specification` in the form ``some.dotted.package_name:relative/path``, making
it possible to address template assets which live in another package.
@@ -409,20 +409,20 @@ To use an environment variable, start your application under a shell using the
``PYRAMID_RELOAD_TEMPLATES`` operating system environment variable set to
``1``, For example:
-.. code-block:: text
+.. code-block:: bash
- $ PYRAMID_RELOAD_TEMPLATES=1 $VENV/bin/pserve myproject.ini
+ PYRAMID_RELOAD_TEMPLATES=1 $VENV/bin/pserve myproject.ini
To use a setting in the application ``.ini`` file for the same purpose, set the
``pyramid.reload_templates`` key to ``true`` within the application's
configuration section, e.g.:
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:main]
- use = egg:MyProject
- pyramid.reload_templates = true
+ [app:main]
+ use = egg:MyProject
+ pyramid.reload_templates = true
.. index::
single: template system bindings
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 594badcb6..8f4d806e6 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -102,17 +102,17 @@ isolated request for the duration of a single test. Here's an example of using
this feature:
.. code-block:: python
- :linenos:
+ :linenos:
- import unittest
- from pyramid import testing
+ import unittest
+ from pyramid import testing
- class MyTest(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp()
+ class MyTest(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
- def tearDown(self):
- testing.tearDown()
+ def tearDown(self):
+ testing.tearDown()
The above will make sure that :func:`~pyramid.threadlocal.get_current_registry`
called within a test case method of ``MyTest`` will return the
@@ -131,18 +131,18 @@ can pass a :term:`request` object into the :func:`pyramid.testing.setUp` within
the ``setUp`` method of your test:
.. code-block:: python
- :linenos:
+ :linenos:
- import unittest
- from pyramid import testing
+ import unittest
+ from pyramid import testing
- class MyTest(unittest.TestCase):
- def setUp(self):
- request = testing.DummyRequest()
- self.config = testing.setUp(request=request)
+ class MyTest(unittest.TestCase):
+ def setUp(self):
+ request = testing.DummyRequest()
+ self.config = testing.setUp(request=request)
- def tearDown(self):
- testing.tearDown()
+ def tearDown(self):
+ testing.tearDown()
If you pass a :term:`request` object into :func:`pyramid.testing.setUp` within
your test case's ``setUp``, any test method attached to the ``MyTest`` test
@@ -165,17 +165,17 @@ under test and :func:`pyramid.testing.tearDown` afterwards.
This style is useful for small self-contained tests. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- import unittest
+ import unittest
- class MyTest(unittest.TestCase):
+ class MyTest(unittest.TestCase):
- def test_my_function(self):
- from pyramid import testing
- with testing.testConfig() as config:
- config.add_route('bar', '/bar/{id}')
- my_function_which_needs_route_bar()
+ def test_my_function(self):
+ from pyramid import testing
+ with testing.testConfig() as config:
+ config.add_route('bar', '/bar/{id}')
+ my_function_which_needs_route_bar()
What?
~~~~~
@@ -208,14 +208,14 @@ For example, let's imagine you want to unit test a :app:`Pyramid` view
function.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPForbidden
+ from pyramid.httpexceptions import HTTPForbidden
- def view_fn(request):
- if request.has_permission('edit'):
- raise HTTPForbidden
- return {'greeting':'hello'}
+ def view_fn(request):
+ if request.has_permission('edit'):
+ raise HTTPForbidden
+ return {'greeting':'hello'}
.. note::
@@ -243,35 +243,35 @@ without needing to invoke the actual application configuration implied by its
:class:`unittest.TestCase` that used the testing API.
.. code-block:: python
- :linenos:
-
- import unittest
- from pyramid import testing
-
- class MyTest(unittest.TestCase):
- def setUp(self):
- self.config = testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def test_view_fn_forbidden(self):
- from pyramid.httpexceptions import HTTPForbidden
- from my.package import view_fn
- self.config.testing_securitypolicy(userid='hank',
- permissive=False)
- request = testing.DummyRequest()
- request.context = testing.DummyResource()
- self.assertRaises(HTTPForbidden, view_fn, request)
-
- def test_view_fn_allowed(self):
- from my.package import view_fn
- self.config.testing_securitypolicy(userid='hank',
- permissive=True)
- request = testing.DummyRequest()
- request.context = testing.DummyResource()
- response = view_fn(request)
- self.assertEqual(response, {'greeting':'hello'})
+ :linenos:
+
+ import unittest
+ from pyramid import testing
+
+ class MyTest(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
+ def test_view_fn_forbidden(self):
+ from pyramid.httpexceptions import HTTPForbidden
+ from my.package import view_fn
+ self.config.testing_securitypolicy(userid='hank',
+ permissive=False)
+ request = testing.DummyRequest()
+ request.context = testing.DummyResource()
+ self.assertRaises(HTTPForbidden, view_fn, request)
+
+ def test_view_fn_allowed(self):
+ from my.package import view_fn
+ self.config.testing_securitypolicy(userid='hank',
+ permissive=True)
+ request = testing.DummyRequest()
+ request.context = testing.DummyResource()
+ response = view_fn(request)
+ self.assertEqual(response, {'greeting':'hello'})
In the above example, we create a ``MyTest`` test case that inherits from
:class:`unittest.TestCase`. If it's in our :app:`Pyramid` application, it will
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index cd8395eac..9b91e21ba 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -116,19 +116,19 @@ is typically used as an application's root factory. Here's an example of a
simple root factory class:
.. code-block:: python
- :linenos:
+ :linenos:
- class Root(dict):
- def __init__(self, request):
- pass
+ class Root(dict):
+ def __init__(self, request):
+ pass
Here's an example of using this root factory within startup configuration, by
passing it to an instance of a :term:`Configurator` named ``config``:
.. code-block:: python
- :linenos:
+ :linenos:
- config = Configurator(root_factory=Root)
+ config = Configurator(root_factory=Root)
The ``root_factory`` argument to the :class:`~pyramid.config.Configurator`
constructor registers this root factory to be called to generate a root
@@ -320,11 +320,11 @@ following resource tree:
.. code-block:: text
- /--
- |
- |-- foo
- |
- ----bar
+ /--
+ |
+ |-- foo
+ |
+ ----bar
Here's what happens:
@@ -366,15 +366,15 @@ However, for this tree:
.. code-block:: text
- /--
- |
- |-- foo
- |
- ----bar
- |
- ----baz
- |
- biz
+ /--
+ |
+ |-- foo
+ |
+ ----bar
+ |
+ ----baz
+ |
+ biz
The user asks for ``http://example.com/foo/bar/baz/biz/buz.txt``
@@ -461,17 +461,17 @@ the :func:`zope.interface.implementer` class decorator to associate the
interface with the class.
.. code-block:: python
- :linenos:
+ :linenos:
- from zope.interface import Interface
- from zope.interface import implementer
+ from zope.interface import Interface
+ from zope.interface import implementer
- class IHello(Interface):
- """ A marker interface """
+ class IHello(Interface):
+ """ A marker interface """
- @implementer(IHello)
- class Hello(object):
- pass
+ @implementer(IHello)
+ class Hello(object):
+ pass
To attach an interface to a resource *instance*, you define the interface and
use the :func:`zope.interface.alsoProvides` function to associate the interface
@@ -479,21 +479,21 @@ with the instance. This function mutates the instance in such a way that the
interface is attached to it.
.. code-block:: python
- :linenos:
+ :linenos:
- from zope.interface import Interface
- from zope.interface import alsoProvides
+ from zope.interface import Interface
+ from zope.interface import alsoProvides
- class IHello(Interface):
- """ A marker interface """
+ class IHello(Interface):
+ """ A marker interface """
- class Hello(object):
- pass
+ class Hello(object):
+ pass
- def make_hello():
- hello = Hello()
- alsoProvides(hello, IHello)
- return hello
+ def make_hello():
+ hello = Hello()
+ alsoProvides(hello, IHello)
+ return hello
Regardless of how you associate an interface—with either a resource instance
or a resource class—the resulting code to associate that interface with a view
@@ -504,12 +504,12 @@ interface lives in the root of your application, and its module is named
this interface.
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_view('mypackage.views.hello_world', name='hello.html',
- context='mypackage.resources.IHello')
+ config.add_view('mypackage.views.hello_world', name='hello.html',
+ context='mypackage.resources.IHello')
Any time a resource that is determined to be the :term:`context` provides this
interface, and a view named ``hello.html`` is looked up against it as per the
diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst
index 6db61a579..2ca162c46 100644
--- a/docs/narr/upgrading.rst
+++ b/docs/narr/upgrading.rst
@@ -124,7 +124,7 @@ you can see DeprecationWarnings printed to the console when the tests run.
.. code-block:: bash
- $ python -Wd setup.py test -q
+ python -Wd setup.py test -q
The ``-Wd`` argument tells Python to print deprecation warnings to the console.
See `the Python -W flag documentation
@@ -137,19 +137,19 @@ deprecation warning from being issued. For example:
.. code-block:: bash
- $ python -Wd setup.py test -q
- # .. elided ...
- running build_ext
- /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
- DeprecationWarning: static: The "pyramid.view.static" class is deprecated
- as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
- the "use_subpath" argument set to True.
- from pyramid.view import static
- .
- ----------------------------------------------------------------------
- Ran 1 test in 0.014s
-
- OK
+ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
+ DeprecationWarning: static: The "pyramid.view.static" class is deprecated
+ as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
+ the "use_subpath" argument set to True.
+ from pyramid.view import static
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
In the above case, it's line #3 in the ``myproj.views`` module (``from
pyramid.view import static``) that is causing the problem:
@@ -178,14 +178,14 @@ console:
.. code-block:: bash
- $ python -Wd setup.py test -q
- # .. elided ...
- running build_ext
- .
- ----------------------------------------------------------------------
- Ran 1 test in 0.014s
-
- OK
+ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
My application doesn't have any tests or has few tests
@@ -197,18 +197,18 @@ deprecation warnings won't be executed.
In this circumstance, you can start your application interactively under a
server run with the ``PYTHONWARNINGS`` environment variable set to ``default``.
-On UNIX, you can do that via:
+On Unix, you can do that via:
.. code-block:: bash
- $ PYTHONWARNINGS=default $VENV/bin/pserve development.ini
+ PYTHONWARNINGS=default $VENV/bin/pserve development.ini
On Windows, you need to issue two commands:
.. code-block:: doscon
- c:\> set PYTHONWARNINGS=default
- c:\> Scripts\pserve development.ini
+ set PYTHONWARNINGS=default
+ Scripts\pserve development.ini
At this point, it's ensured that deprecation warnings will be printed to the
console whenever a codepath is hit that generates one. You can then click
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 00c7bd3bf..52d64891c 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -57,12 +57,12 @@ example:
.. code-block:: python
- # "config" below is presumed to be an instance of the
- # pyramid.config.Configurator class; "myview" is assumed
- # to be a "view callable" function
- from views import myview
- config.add_route('myroute', '/prefix/{one}/{two}')
- config.add_view(myview, route_name='myroute')
+ # "config" below is presumed to be an instance of the
+ # pyramid.config.Configurator class; "myview" is assumed
+ # to be a "view callable" function
+ from views import myview
+ config.add_route('myroute', '/prefix/{one}/{two}')
+ config.add_view(myview, route_name='myroute')
When a :term:`view callable` added to the configuration by way of
:meth:`~pyramid.config.Configurator.add_view` becomes associated with a route
@@ -76,8 +76,8 @@ a portion of your project's ``__init__.py``:
.. code-block:: python
- config.add_route('myroute', '/prefix/{one}/{two}')
- config.scan('mypackage')
+ config.add_route('myroute', '/prefix/{one}/{two}')
+ config.scan('mypackage')
Note that we don't call :meth:`~pyramid.config.Configurator.add_view` in this
setup code. However, the above :term:`scan` execution
@@ -90,12 +90,12 @@ references ``myroute`` as a ``route_name`` parameter:
.. code-block:: python
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='myroute')
- def myview(request):
- return Response('OK')
+ @view_config(route_name='myroute')
+ def myview(request):
+ return Response('OK')
The above combination of ``add_route`` and ``scan`` is completely equivalent to
using the previous combination of ``add_route`` and ``add_view``.
@@ -120,13 +120,13 @@ equivalent:
.. code-block:: text
- {foo}/bar/baz
+ {foo}/bar/baz
and:
.. code-block:: text
- /{foo}/bar/baz
+ /{foo}/bar/baz
If a pattern is a valid URL it won't be matched against an incoming request.
Instead it can be useful for generating external URLs. See :ref:`External
@@ -159,21 +159,21 @@ two replacement markers (``baz``, and ``bar``):
.. code-block:: text
- foo/{baz}/{bar}
+ foo/{baz}/{bar}
The above pattern will match these URLs, generating the following matchdicts:
.. code-block:: text
- foo/1/2 -> {'baz':u'1', 'bar':u'2'}
- foo/abc/def -> {'baz':u'abc', 'bar':u'def'}
+ foo/1/2 -> {'baz':u'1', 'bar':u'2'}
+ foo/abc/def -> {'baz':u'abc', 'bar':u'def'}
It will not match the following patterns however:
.. code-block:: text
- foo/1/2/ -> No match (trailing slash)
- bar/abc/def -> First segment literal mismatch
+ foo/1/2/ -> No match (trailing slash)
+ bar/abc/def -> First segment literal mismatch
The match for a segment replacement marker in a segment will be done only up to
the first non-alphanumeric character in the segment in the pattern. So, for
@@ -181,7 +181,7 @@ instance, if this route pattern was used:
.. code-block:: text
- foo/{name}.html
+ foo/{name}.html
The literal path ``/foo/biz.html`` will match the above route pattern, and the
match result will be ``{'name':u'biz'}``. However, the literal path
@@ -230,19 +230,19 @@ following pattern:
.. code-block:: text
- foo/{bar}
+ foo/{bar}
When matching the following URL:
.. code-block:: text
- http://example.com/foo/La%20Pe%C3%B1a
+ http://example.com/foo/La%20Pe%C3%B1a
The matchdict will look like so (the value is URL-decoded / UTF-8 decoded):
.. code-block:: text
- {'bar':u'La Pe\xf1a'}
+ {'bar':u'La Pe\xf1a'}
Literal strings in the path segment should represent the *decoded* value of the
``PATH_INFO`` provided to Pyramid. You don't want to use a URL-encoded value
@@ -251,13 +251,13 @@ example, rather than this:
.. code-block:: text
- /Foo%20Bar/{baz}
+ /Foo%20Bar/{baz}
You'll want to use something like this:
.. code-block:: text
- /Foo Bar/{baz}
+ /Foo Bar/{baz}
For patterns that contain "high-order" characters in its literals, you'll want
to use a Unicode value as the pattern as opposed to any URL-encoded or
@@ -266,7 +266,7 @@ pattern like this:
.. code-block:: text
- /La Pe\xc3\xb1a/{x}
+ /La Pe\xc3\xb1a/{x}
But this will either cause an error at startup time or it won't match properly.
You'll want to use a Unicode value as the pattern instead rather than raw
@@ -277,14 +277,14 @@ Unicode pattern in the source, like so:
.. code-block:: text
- /La Peña/{x}
+ /La Peña/{x}
Or you can ignore source file encoding and use equivalent Unicode escape
characters in the pattern.
.. code-block:: text
- /La Pe\xf1a/{x}
+ /La Pe\xf1a/{x}
Dynamic segment names cannot contain high-order characters, so this applies
only to literals in the pattern.
@@ -296,17 +296,17 @@ For example:
.. code-block:: text
- foo/{baz}/{bar}*fizzle
+ foo/{baz}/{bar}*fizzle
The above pattern will match these URLs, generating the following matchdicts:
.. code-block:: text
- foo/1/2/ ->
- {'baz':u'1', 'bar':u'2', 'fizzle':()}
+ foo/1/2/ ->
+ {'baz':u'1', 'bar':u'2', 'fizzle':()}
- foo/abc/def/a/b/c ->
- {'baz':u'abc', 'bar':u'def', 'fizzle':(u'a', u'b', u'c')}
+ foo/abc/def/a/b/c ->
+ {'baz':u'abc', 'bar':u'def', 'fizzle':(u'a', u'b', u'c')}
Note that when a ``*stararg`` remainder match is matched, the value put into
the matchdict is turned into a tuple of path segments representing the
@@ -315,19 +315,19 @@ UTF-8 into Unicode. For example, for the following pattern:
.. code-block:: text
- foo/*fizzle
+ foo/*fizzle
When matching the following path:
.. code-block:: text
- /foo/La%20Pe%C3%B1a/a/b/c
+ /foo/La%20Pe%C3%B1a/a/b/c
Will generate the following matchdict:
.. code-block:: text
- {'fizzle':(u'La Pe\xf1a', u'a', u'b', u'c')}
+ {'fizzle':(u'La Pe\xf1a', u'a', u'b', u'c')}
By default, the ``*stararg`` will parse the remainder sections into a tuple
split by segment. Changing the regular expression used to match a marker can
@@ -341,8 +341,8 @@ The above pattern will match these URLs, generating the following matchdicts:
.. code-block:: text
- foo/1/2/ -> {'baz':u'1', 'bar':u'2', 'fizzle':u''}
- foo/abc/def/a/b/c -> {'baz':u'abc', 'bar':u'def', 'fizzle': u'a/b/c'}
+ foo/1/2/ -> {'baz':u'1', 'bar':u'2', 'fizzle':u''}
+ foo/abc/def/a/b/c -> {'baz':u'abc', 'bar':u'def', 'fizzle': u'a/b/c'}
This occurs because the default regular expression for a marker is ``[^/]+``
which will match everything up to the first ``/``, while ``{fizzle:.*}`` will
@@ -372,8 +372,8 @@ be added in the following order:
.. code-block:: text
- members/{def}
- members/abc
+ members/{def}
+ members/abc
In such a configuration, the ``members/abc`` pattern would *never* be matched.
This is because the match ordering will always match ``members/{def}`` first;
@@ -518,14 +518,14 @@ will be the string ``'1'``, ex.: ``{'id':'1'}``.
The ``mypackage.views`` module referred to above might look like so:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='idea')
- def site_view(request):
- return Response(request.matchdict['id'])
+ @view_config(route_name='idea')
+ def site_view(request):
+ return Response(request.matchdict['id'])
The view has access to the matchdict directly via the request, and can access
variables within it that match keys present as a result of the route pattern.
@@ -540,43 +540,43 @@ Below is an example of a more complicated set of route statements you might add
to your application:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('idea', 'ideas/{idea}')
- config.add_route('user', 'users/{user}')
- config.add_route('tag', 'tags/{tag}')
- config.scan()
+ config.add_route('idea', 'ideas/{idea}')
+ config.add_route('user', 'users/{user}')
+ config.add_route('tag', 'tags/{tag}')
+ config.scan()
Here is an example of a corresponding ``mypackage.views`` module:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='idea')
- def idea_view(request):
- return Response(request.matchdict['idea'])
+ @view_config(route_name='idea')
+ def idea_view(request):
+ return Response(request.matchdict['idea'])
- @view_config(route_name='user')
- def user_view(request):
- user = request.matchdict['user']
- return Response(u'The user is {}.'.format(user))
-
- @view_config(route_name='tag')
- def tag_view(request):
- tag = request.matchdict['tag']
- return Response(u'The tag is {}.'.format(tag))
+ @view_config(route_name='user')
+ def user_view(request):
+ user = request.matchdict['user']
+ return Response(u'The user is {}.'.format(user))
+
+ @view_config(route_name='tag')
+ def tag_view(request):
+ tag = request.matchdict['tag']
+ return Response(u'The tag is {}.'.format(tag))
The above configuration will allow :app:`Pyramid` to service URLs in these
forms:
.. code-block:: text
- /ideas/{idea}
- /users/{user}
- /tags/{tag}
+ /ideas/{idea}
+ /users/{user}
+ /tags/{tag}
- When a URL matches the pattern ``/ideas/{idea}``, the view callable
available at the dotted Python pathname ``mypackage.views.idea_view`` will
@@ -614,33 +614,33 @@ an instance of a class that will be the context resource used by the view.
An example of using a route with a factory:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('idea', 'ideas/{idea}', factory='myproject.resources.Idea')
- config.scan()
+ config.add_route('idea', 'ideas/{idea}', factory='myproject.resources.Idea')
+ config.scan()
The above route will manufacture an ``Idea`` resource as a :term:`context`,
assuming that ``mypackage.resources.Idea`` resolves to a class that accepts a
request in its ``__init__``. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- class Idea(object):
- def __init__(self, request):
- pass
+ class Idea(object):
+ def __init__(self, request):
+ pass
In a more complicated application, this root factory might be a class
representing a :term:`SQLAlchemy` model. The view ``mypackage.views.idea_view``
might look like this:
.. code-block:: python
- :linenos:
+ :linenos:
- @view_config(route_name='idea')
- def idea_view(request):
- idea = request.context
- return Response(idea)
+ @view_config(route_name='idea')
+ def idea_view(request):
+ idea = request.context
+ return Response(idea)
Here, ``request.context`` is an instance of ``Idea``. If indeed the resource
object is a SQLAlchemy model, you do not even have to perform a query in the
@@ -661,16 +661,16 @@ It's not entirely obvious how to use a route pattern to match the root URL
:meth:`~pyramid.config.Configurator.add_route`:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('root', '')
+ config.add_route('root', '')
Or provide the literal string ``/`` as the pattern:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('root', '/')
+ config.add_route('root', '/')
.. index::
single: generating route URLs
@@ -686,9 +686,9 @@ on route patterns. For example, if you've configured a route with the ``name``
"foo" and the ``pattern`` "{a}/{b}/{c}", you might do this.
.. code-block:: python
- :linenos:
+ :linenos:
- url = request.route_url('foo', a='1', b='2', c='3')
+ url = request.route_url('foo', a='1', b='2', c='3')
This would return something like the string ``http://example.com/1/2/3`` (at
least if the current protocol and hostname implied ``http://example.com``).
@@ -699,7 +699,7 @@ To generate only the *path* portion of a URL from a route, use the
.. code-block:: python
- url = request.route_path('foo', a='1', b='2', c='3')
+ url = request.route_path('foo', a='1', b='2', c='3')
This will return the string ``/1/2/3`` rather than a full URL.
@@ -714,51 +714,51 @@ Therefore, if you've added a route like so:
.. code-block:: python
- config.add_route('la', u'/La Peña/{city}')
+ config.add_route('la', u'/La Peña/{city}')
And you later generate a URL using ``route_path`` or ``route_url`` like so:
.. code-block:: python
- url = request.route_path('la', city=u'Québec')
+ url = request.route_path('la', city=u'Québec')
You will wind up with the path encoded to UTF-8 and URL-quoted like so:
.. code-block:: text
- /La%20Pe%C3%B1a/Qu%C3%A9bec
+ /La%20Pe%C3%B1a/Qu%C3%A9bec
If you have a ``*stararg`` remainder dynamic part of your route pattern:
.. code-block:: python
- config.add_route('abc', 'a/b/c/*foo')
+ config.add_route('abc', 'a/b/c/*foo')
And you later generate a URL using ``route_path`` or ``route_url`` using a
*string* as the replacement value:
.. code-block:: python
- url = request.route_path('abc', foo=u'Québec/biz')
+ url = request.route_path('abc', foo=u'Québec/biz')
The value you pass will be URL-quoted except for embedded slashes in the
result:
.. code-block:: text
- /a/b/c/Qu%C3%A9bec/biz
+ /a/b/c/Qu%C3%A9bec/biz
You can get a similar result by passing a tuple composed of path elements:
.. code-block:: python
- url = request.route_path('abc', foo=(u'Québec', u'biz'))
+ url = request.route_path('abc', foo=(u'Québec', u'biz'))
Each value in the tuple will be URL-quoted and joined by slashes in this case:
.. code-block:: text
- /a/b/c/Qu%C3%A9bec/biz
+ /a/b/c/Qu%C3%A9bec/biz
.. index::
single: static routes
@@ -771,10 +771,10 @@ Static Routes
Routes may be added with a ``static`` keyword argument. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- config = Configurator()
- config.add_route('page', '/page/{action}', static=True)
+ config = Configurator()
+ config.add_route('page', '/page/{action}', static=True)
Routes added with a ``True`` ``static`` keyword argument will never be
considered for matching at request time. Static routes are useful for URL
@@ -802,14 +802,14 @@ Route patterns that are valid URLs, are treated as external routes. Like
:ref:`static routes <static_route_narr>` they are useful for URL generation
purposes only and are never considered for matching at request time.
-.. code-block:: python
- :linenos:
+.. code-block:: pycon
+ :linenos:
- >>> config = Configurator()
- >>> config.add_route('youtube', 'https://youtube.com/watch/{video_id}')
- ...
- >>> request.route_url('youtube', video_id='oHg5SJYRHA0')
- >>> "https://youtube.com/watch/oHg5SJYRHA0"
+ >>> config = Configurator()
+ >>> config.add_route('youtube', 'https://youtube.com/watch/{video_id}')
+ ...
+ >>> request.route_url('youtube', video_id='oHg5SJYRHA0')
+ >>> "https://youtube.com/watch/oHg5SJYRHA0"
Most pattern replacements and calls to
:meth:`pyramid.request.Request.route_url` will work as expected. However, calls
@@ -845,26 +845,26 @@ Let's use an example. If the following routes are configured in your
application:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPNotFound
+ from pyramid.httpexceptions import HTTPNotFound
- def notfound(request):
- return HTTPNotFound()
+ def notfound(request):
+ return HTTPNotFound()
- def no_slash(request):
- return Response('No slash')
+ def no_slash(request):
+ return Response('No slash')
- def has_slash(request):
- return Response('Has slash')
+ def has_slash(request):
+ return Response('Has slash')
- def main(g, **settings):
- config = Configurator()
- config.add_route('noslash', 'no_slash')
- config.add_route('hasslash', 'has_slash/')
- config.add_view(no_slash, route_name='noslash')
- config.add_view(has_slash, route_name='hasslash')
- config.add_notfound_view(notfound, append_slash=True)
+ def main(g, **settings):
+ config = Configurator()
+ config.add_route('noslash', 'no_slash')
+ config.add_route('hasslash', 'has_slash/')
+ config.add_view(no_slash, route_name='noslash')
+ config.add_view(has_slash, route_name='hasslash')
+ config.add_notfound_view(notfound, append_slash=True)
If a request enters the application with the ``PATH_INFO`` value of
``/no_slash``, the first route will match and the browser will show "No slash".
@@ -885,28 +885,28 @@ and :class:`pyramid.view.view_config` decorators and a :term:`scan` to do
exactly the same job:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPNotFound
- from pyramid.view import notfound_view_config, view_config
+ from pyramid.httpexceptions import HTTPNotFound
+ from pyramid.view import notfound_view_config, view_config
- @notfound_view_config(append_slash=True)
- def notfound(request):
- return HTTPNotFound()
+ @notfound_view_config(append_slash=True)
+ def notfound(request):
+ return HTTPNotFound()
- @view_config(route_name='noslash')
- def no_slash(request):
- return Response('No slash')
+ @view_config(route_name='noslash')
+ def no_slash(request):
+ return Response('No slash')
- @view_config(route_name='hasslash')
- def has_slash(request):
- return Response('Has slash')
+ @view_config(route_name='hasslash')
+ def has_slash(request):
+ return Response('Has slash')
- def main(g, **settings):
- config = Configurator()
- config.add_route('noslash', 'no_slash')
- config.add_route('hasslash', 'has_slash/')
- config.scan()
+ def main(g, **settings):
+ config = Configurator()
+ config.add_route('noslash', 'no_slash')
+ config.add_route('hasslash', 'has_slash/')
+ config.scan()
.. warning::
@@ -937,7 +937,7 @@ which you started the application from. For example:
.. code-block:: text
:linenos:
- $ PYRAMID_DEBUG_ROUTEMATCH=true $VENV/bin/pserve development.ini
+ PYRAMID_DEBUG_ROUTEMATCH=true $VENV/bin/pserve development.ini
Starting server in PID 13586.
serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
2010-12-16 14:45:19,956 no route matched for url \
@@ -980,16 +980,16 @@ callable's author intended while still maintaining the same route names. For
example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def users_include(config):
- config.add_route('show_users', '/show')
+ def users_include(config):
+ config.add_route('show_users', '/show')
- def main(global_config, **settings):
- config = Configurator()
- config.include(users_include, route_prefix='/users')
+ def main(global_config, **settings):
+ config = Configurator()
+ config.include(users_include, route_prefix='/users')
In the above configuration, the ``show_users`` route will have an effective
route pattern of ``/users/show`` instead of ``/show`` because the
@@ -1003,20 +1003,20 @@ turns around and includes another callable, the second-level route prefix will
be prepended with the first:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def timing_include(config):
- config.add_route('show_times', '/times')
+ def timing_include(config):
+ config.add_route('show_times', '/times')
- def users_include(config):
- config.add_route('show_users', '/show')
- config.include(timing_include, route_prefix='/timing')
+ def users_include(config):
+ config.add_route('show_users', '/show')
+ config.include(timing_include, route_prefix='/timing')
- def main(global_config, **settings):
- config = Configurator()
- config.include(users_include, route_prefix='/users')
+ def main(global_config, **settings):
+ config = Configurator()
+ config.include(users_include, route_prefix='/users')
In the above configuration, the ``show_users`` route will still have an
effective route pattern of ``/users/show``. The ``show_times`` route, however,
@@ -1030,38 +1030,38 @@ your route names so they'll be unlikely to conflict with other packages that
may be added in the future. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def timing_include(config):
- config.add_route('timing.show_times', '/times')
+ def timing_include(config):
+ config.add_route('timing.show_times', '/times')
- def users_include(config):
- config.add_route('users.show_users', '/show')
- config.include(timing_include, route_prefix='/timing')
+ def users_include(config):
+ config.add_route('users.show_users', '/show')
+ config.include(timing_include, route_prefix='/timing')
- def main(global_config, **settings):
- config = Configurator()
- config.include(users_include, route_prefix='/users')
+ def main(global_config, **settings):
+ config = Configurator()
+ config.include(users_include, route_prefix='/users')
A convenience context manager exists to set the route prefix for any
:meth:`pyramid.config.Configurator.add_route` or
:meth:`pyramid.config.Configurator.include` calls within the context.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def timing_include(config):
- config.add_route('timing.show_times', '/times')
+ def timing_include(config):
+ config.add_route('timing.show_times', '/times')
- def main(global_config, **settings)
- config = Configurator()
- with config.route_prefix_context('/timing'):
- config.include(timing_include)
- config.add_route('timing.average', '/average')
+ def main(global_config, **settings)
+ config = Configurator()
+ with config.route_prefix_context('/timing'):
+ config.include(timing_include)
+ config.add_route('timing.average', '/average')
.. index::
single: route predicates (custom)
@@ -1087,18 +1087,18 @@ object).
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- def any_of(segment_name, *allowed):
- def predicate(info, request):
- if info['match'][segment_name] in allowed:
- return True
- return predicate
+ def any_of(segment_name, *allowed):
+ def predicate(info, request):
+ if info['match'][segment_name] in allowed:
+ return True
+ return predicate
- num_one_two_or_three = any_of('num', 'one', 'two', 'three')
+ num_one_two_or_three = any_of('num', 'one', 'two', 'three')
- config.add_route('route_to_num', '/{num}',
- custom_predicates=(num_one_two_or_three,))
+ config.add_route('route_to_num', '/{num}',
+ custom_predicates=(num_one_two_or_three,))
The above ``any_of`` function generates a predicate which ensures that the
match value named ``segment_name`` is in the set of allowable values
@@ -1113,23 +1113,23 @@ A custom route predicate may also *modify* the ``match`` dictionary. For
instance, a predicate might do some type conversion of values:
.. code-block:: python
- :linenos:
+ :linenos:
- def integers(*segment_names):
- def predicate(info, request):
- match = info['match']
- for segment_name in segment_names:
- try:
- match[segment_name] = int(match[segment_name])
- except (TypeError, ValueError):
- pass
- return True
- return predicate
+ def integers(*segment_names):
+ def predicate(info, request):
+ match = info['match']
+ for segment_name in segment_names:
+ try:
+ match[segment_name] = int(match[segment_name])
+ except (TypeError, ValueError):
+ pass
+ return True
+ return predicate
- ymd_to_int = integers('year', 'month', 'day')
+ ymd_to_int = integers('year', 'month', 'day')
- config.add_route('ymd', '/{year}/{month}/{day}',
- custom_predicates=(ymd_to_int,))
+ config.add_route('ymd', '/{year}/{month}/{day}',
+ custom_predicates=(ymd_to_int,))
Note that a conversion predicate is still a predicate, so it must return
``True`` or ``False``. A predicate that does *only* conversion, such as the one
@@ -1203,35 +1203,35 @@ will help you with the ``pviews`` command (see
If a predicate is a class, just add ``__text__`` property in a standard manner.
.. code-block:: python
- :linenos:
+ :linenos:
- class DummyCustomPredicate1(object):
- def __init__(self):
- self.__text__ = 'my custom class predicate'
+ class DummyCustomPredicate1(object):
+ def __init__(self):
+ self.__text__ = 'my custom class predicate'
- class DummyCustomPredicate2(object):
- __text__ = 'my custom class predicate'
+ class DummyCustomPredicate2(object):
+ __text__ = 'my custom class predicate'
If a predicate is a method, you'll need to assign it after method declaration
(see `PEP 232 <https://www.python.org/dev/peps/pep-0232/>`_).
.. code-block:: python
- :linenos:
+ :linenos:
- def custom_predicate():
- pass
- custom_predicate.__text__ = 'my custom method predicate'
+ def custom_predicate():
+ pass
+ custom_predicate.__text__ = 'my custom method predicate'
If a predicate is a classmethod, using ``@classmethod`` will not work, but you
can still easily do it by wrapping it in a classmethod call.
.. code-block:: python
- :linenos:
+ :linenos:
- def classmethod_predicate():
- pass
- classmethod_predicate.__text__ = 'my classmethod predicate'
- classmethod_predicate = classmethod(classmethod_predicate)
+ def classmethod_predicate():
+ pass
+ classmethod_predicate.__text__ = 'my classmethod predicate'
+ classmethod_predicate = classmethod(classmethod_predicate)
The same will work with ``staticmethod``, using ``staticmethod`` instead of
``classmethod``.
@@ -1258,11 +1258,11 @@ This object will usually be used as the :term:`context` resource of the view
callable ultimately found via :term:`view lookup`.
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_route('abc', '/abc',
- factory='myproject.resources.root_factory')
- config.add_view('myproject.views.theview', route_name='abc')
+ config.add_route('abc', '/abc',
+ factory='myproject.resources.root_factory')
+ config.add_view('myproject.views.theview', route_name='abc')
The factory can either be a Python object or a :term:`dotted Python name` (a
string) which points to such a Python object, as it is above.
@@ -1275,11 +1275,11 @@ A factory must be a callable which accepts a request and returns an arbitrary
Python object. For example, the below class can be used as a factory:
.. code-block:: python
- :linenos:
+ :linenos:
- class Mine(object):
- def __init__(self, request):
- pass
+ class Mine(object):
+ def __init__(self, request):
+ pass
A route factory is actually conceptually identical to the :term:`root factory`
described at :ref:`the_resource_tree`.
@@ -1310,14 +1310,14 @@ factory which attaches a custom ``__acl__`` to an object at its creation time.
Such a ``factory`` might look like so:
.. code-block:: python
- :linenos:
-
- class Article(object):
- def __init__(self, request):
- matchdict = request.matchdict
- article = matchdict.get('article', None)
- if article == '1':
- self.__acl__ = [ (Allow, 'editor', 'view') ]
+ :linenos:
+
+ class Article(object):
+ def __init__(self, request):
+ matchdict = request.matchdict
+ article = matchdict.get('article', None)
+ if article == '1':
+ self.__acl__ = [ (Allow, 'editor', 'view') ]
If the route ``archives/{article}`` is matched, and the article number is
``1``, :app:`Pyramid` will generate an ``Article`` :term:`context` resource
diff --git a/docs/narr/vhosting.rst b/docs/narr/vhosting.rst
index 8902e8bae..f3570331a 100644
--- a/docs/narr/vhosting.rst
+++ b/docs/narr/vhosting.rst
@@ -42,14 +42,14 @@ Here's an example of a PasteDeploy configuration snippet that includes a
``rutter`` composite.
.. code-block:: ini
- :linenos:
+ :linenos:
- [app:mypyramidapp]
- use = egg:mypyramidapp
+ [app:mypyramidapp]
+ use = egg:mypyramidapp
- [composite:main]
- use = egg:rutter#urlmap
- /pyramidapp = mypyramidapp
+ [composite:main]
+ use = egg:rutter#urlmap
+ /pyramidapp = mypyramidapp
This "roots" the :app:`Pyramid` application at the prefix ``/pyramidapp`` and
serves up the composite as the "main" application in the file.
@@ -68,9 +68,9 @@ in your ``.ini`` file. The ``WSGIScriptAlias`` configuration setting in a
:term:`mod_wsgi` configuration does the work for you:
.. code-block:: apache
- :linenos:
+ :linenos:
- WSGIScriptAlias /pyramidapp /Users/chrism/projects/modwsgi/env/pyramid.wsgi
+ WSGIScriptAlias /pyramidapp /Users/chrism/projects/modwsgi/env/pyramid.wsgi
In the above configuration, we root a :app:`Pyramid` application at
``/pyramidapp`` within the Apache configuration.
diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst
index 3b683ff79..c463d297e 100644
--- a/docs/narr/viewconfig.rst
+++ b/docs/narr/viewconfig.rst
@@ -134,7 +134,7 @@ Non-Predicate Arguments
When the renderer is a path—although a path is usually just a simple relative
pathname (e.g., ``templates/foo.pt``, implying that a template named "foo.pt"
is in the "templates" directory relative to the directory of the current
- :term:`package`)—the path can be absolute, starting with a slash on UNIX or a
+ :term:`package`)—the path can be absolute, starting with a slash on Unix or a
drive letter prefix on Windows. The path can alternatively be a :term:`asset
specification` in the form ``some.dotted.package_name:relative/path``, making
it possible to address template assets which live in a separate package.
@@ -267,15 +267,15 @@ Non-Predicate Arguments
.. code-block:: python
- def log_timer(wrapped):
- def wrapper(context, request):
- start = time.time()
- response = wrapped(context, request)
- duration = time.time() - start
- response.headers['X-View-Time'] = '%.3f' % (duration,)
- log.info('view took %.3f seconds', duration)
- return response
- return wrapper
+ def log_timer(wrapped):
+ def wrapper(context, request):
+ start = time.time()
+ response = wrapped(context, request)
+ duration = time.time() - start
+ response.headers['X-View-Time'] = '%.3f' % (duration,)
+ log.info('view took %.3f seconds', duration)
+ return response
+ return wrapper
``mapper``
A Python object or :term:`dotted Python name` which refers to a :term:`view
@@ -546,15 +546,15 @@ You can invert the meaning of any predicate value by wrapping it in a call to
:class:`pyramid.config.not_`.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import not_
+ from pyramid.config import not_
- config.add_view(
- 'mypackage.views.my_view',
- route_name='ok',
- request_method=not_('POST')
- )
+ config.add_view(
+ 'mypackage.views.my_view',
+ route_name='ok',
+ request_method=not_('POST')
+ )
The above example will ensure that the view is called if the request method is
*not* ``POST``, at least if no other view is more specific.
@@ -593,37 +593,37 @@ Here's an example of the :class:`~pyramid.view.view_config` decorator that
lives within a :app:`Pyramid` application module ``views.py``:
.. code-block:: python
- :linenos:
+ :linenos:
- from resources import MyResource
- from pyramid.view import view_config
- from pyramid.response import Response
+ from resources import MyResource
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='ok', request_method='POST', permission='read')
- def my_view(request):
- return Response('OK')
+ @view_config(route_name='ok', request_method='POST', permission='read')
+ def my_view(request):
+ return Response('OK')
Using this decorator as above replaces the need to add this imperative
configuration stanza:
.. code-block:: python
- :linenos:
+ :linenos:
- config.add_view('mypackage.views.my_view', route_name='ok',
- request_method='POST', permission='read')
+ config.add_view('mypackage.views.my_view', route_name='ok',
+ request_method='POST', permission='read')
All arguments to ``view_config`` may be omitted. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config()
- def my_view(request):
- """ My view """
- return Response()
+ @view_config()
+ def my_view(request):
+ """ My view """
+ return Response()
Such a registration as the one directly above implies that the view name will
be ``my_view``, registered with a ``context`` argument that matches any
@@ -637,11 +637,11 @@ with your configuration declarations, it doesn't process them. To make
*must* use the ``scan`` method of a :class:`pyramid.config.Configurator`:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is assumed to be an instance of the
- # pyramid.config.Configurator class
- config.scan()
+ # config is assumed to be an instance of the
+ # pyramid.config.Configurator class
+ config.scan()
Please see :ref:`decorations_and_code_scanning` for detailed information about
what happens when code is scanned for configuration declarations resulting from
@@ -674,65 +674,65 @@ in your application.
If your view callable is a function, it may be used as a function decorator:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='edit')
- def edit(request):
- return Response('edited!')
+ @view_config(route_name='edit')
+ def edit(request):
+ return Response('edited!')
If your view callable is a class, the decorator can also be used as a class
decorator. All the arguments to the decorator are the same when applied against
a class as when they are applied against a function. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config(route_name='hello')
- class MyView(object):
- def __init__(self, request):
- self.request = request
+ @view_config(route_name='hello')
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
- def __call__(self):
- return Response('hello')
+ def __call__(self):
+ return Response('hello')
More than one :class:`~pyramid.view.view_config` decorator can be stacked on
top of any number of others. Each decorator creates a separate view
registration. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_config(route_name='edit')
- @view_config(route_name='change')
- def edit(request):
- return Response('edited!')
+ @view_config(route_name='edit')
+ @view_config(route_name='change')
+ def edit(request):
+ return Response('edited!')
This registers the same view under two different names.
The decorator can also be used against a method of a class:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- class MyView(object):
- def __init__(self, request):
- self.request = request
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
- @view_config(route_name='hello')
- def amethod(self):
- return Response('hello')
+ @view_config(route_name='hello')
+ def amethod(self):
+ return Response('hello')
When the decorator is used against a method of a class, a view is registered
for the *class*, so the class constructor must accept an argument list in one
@@ -747,18 +747,18 @@ example, the above registration implied by the decorator being used against the
``amethod`` method could be written equivalently as follows:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.view import view_config
- @view_config(attr='amethod', route_name='hello')
- class MyView(object):
- def __init__(self, request):
- self.request = request
+ @view_config(attr='amethod', route_name='hello')
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
- def amethod(self):
- return Response('hello')
+ def amethod(self):
+ return Response('hello')
.. index::
@@ -776,16 +776,16 @@ are very similar to the arguments that you provide to the
:class:`~pyramid.view.view_config` decorator. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- def hello_world(request):
- return Response('hello!')
+ def hello_world(request):
+ return Response('hello!')
- # config is assumed to be an instance of the
- # pyramid.config.Configurator class
- config.add_view(hello_world, route_name='hello')
+ # config is assumed to be an instance of the
+ # pyramid.config.Configurator class
+ config.add_view(hello_world, route_name='hello')
The first argument, a :term:`view callable`, is the only required argument. It
must either be a Python object which is the view itself or a :term:`dotted
@@ -816,52 +816,52 @@ actions", all of which are mapped to the same route but different request
methods, instead of this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_config
+ from pyramid.response import Response
- class RESTView(object):
- def __init__(self, request):
- self.request = request
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
- @view_config(route_name='rest', request_method='GET')
- def get(self):
- return Response('get')
+ @view_config(route_name='rest', request_method='GET')
+ def get(self):
+ return Response('get')
- @view_config(route_name='rest', request_method='POST')
- def post(self):
- return Response('post')
+ @view_config(route_name='rest', request_method='POST')
+ def post(self):
+ return Response('post')
- @view_config(route_name='rest', request_method='DELETE')
- def delete(self):
- return Response('delete')
+ @view_config(route_name='rest', request_method='DELETE')
+ def delete(self):
+ return Response('delete')
You can do this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_defaults
- from pyramid.view import view_config
- from pyramid.response import Response
+ from pyramid.view import view_defaults
+ from pyramid.view import view_config
+ from pyramid.response import Response
- @view_defaults(route_name='rest')
- class RESTView(object):
- def __init__(self, request):
- self.request = request
+ @view_defaults(route_name='rest')
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
- @view_config(request_method='GET')
- def get(self):
- return Response('get')
+ @view_config(request_method='GET')
+ def get(self):
+ return Response('get')
- @view_config(request_method='POST')
- def post(self):
- return Response('post')
+ @view_config(request_method='POST')
+ def post(self):
+ return Response('post')
- @view_config(request_method='DELETE')
- def delete(self):
- return Response('delete')
+ @view_config(request_method='DELETE')
+ def delete(self):
+ return Response('delete')
In the above example, we were able to take the ``route_name='rest'`` argument
out of the call to each individual ``@view_config`` statement because we used a
@@ -877,67 +877,67 @@ is passed to that directive as its ``view`` argument. For example, instead of
this:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- from pyramid.config import Configurator
+ from pyramid.response import Response
+ from pyramid.config import Configurator
- class RESTView(object):
- def __init__(self, request):
- self.request = request
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
- def get(self):
- return Response('get')
+ def get(self):
+ return Response('get')
- def post(self):
- return Response('post')
+ def post(self):
+ return Response('post')
- def delete(self):
- return Response('delete')
+ def delete(self):
+ return Response('delete')
- def main(global_config, **settings):
- config = Configurator()
- config.add_route('rest', '/rest')
- config.add_view(
- RESTView, route_name='rest', attr='get', request_method='GET')
- config.add_view(
- RESTView, route_name='rest', attr='post', request_method='POST')
- config.add_view(
- RESTView, route_name='rest', attr='delete', request_method='DELETE')
- return config.make_wsgi_app()
+ def main(global_config, **settings):
+ config = Configurator()
+ config.add_route('rest', '/rest')
+ config.add_view(
+ RESTView, route_name='rest', attr='get', request_method='GET')
+ config.add_view(
+ RESTView, route_name='rest', attr='post', request_method='POST')
+ config.add_view(
+ RESTView, route_name='rest', attr='delete', request_method='DELETE')
+ return config.make_wsgi_app()
To reduce the amount of repetition in the ``config.add_view`` statements, we
can move the ``route_name='rest'`` argument to a ``@view_defaults`` class
decorator on the ``RESTView`` class:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_defaults
- from pyramid.response import Response
- from pyramid.config import Configurator
+ from pyramid.view import view_defaults
+ from pyramid.response import Response
+ from pyramid.config import Configurator
- @view_defaults(route_name='rest')
- class RESTView(object):
- def __init__(self, request):
- self.request = request
+ @view_defaults(route_name='rest')
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
- def get(self):
- return Response('get')
+ def get(self):
+ return Response('get')
- def post(self):
- return Response('post')
+ def post(self):
+ return Response('post')
- def delete(self):
- return Response('delete')
+ def delete(self):
+ return Response('delete')
- def main(global_config, **settings):
- config = Configurator()
- config.add_route('rest', '/rest')
- config.add_view(RESTView, attr='get', request_method='GET')
- config.add_view(RESTView, attr='post', request_method='POST')
- config.add_view(RESTView, attr='delete', request_method='DELETE')
- return config.make_wsgi_app()
+ def main(global_config, **settings):
+ config = Configurator()
+ config.add_route('rest', '/rest')
+ config.add_view(RESTView, attr='get', request_method='GET')
+ config.add_view(RESTView, attr='post', request_method='POST')
+ config.add_view(RESTView, attr='delete', request_method='DELETE')
+ return config.make_wsgi_app()
:class:`pyramid.view.view_defaults` accepts the same set of arguments that
:class:`pyramid.view.view_config` does, and they have the same meaning. Each
@@ -948,14 +948,14 @@ Normal Python inheritance rules apply to defaults added via ``view_defaults``.
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- @view_defaults(route_name='rest')
- class Foo(object):
- pass
+ @view_defaults(route_name='rest')
+ class Foo(object):
+ pass
- class Bar(Foo):
- pass
+ class Bar(Foo):
+ pass
The ``Bar`` class above will inherit its view defaults from the arguments
passed to the ``view_defaults`` decorator of the ``Foo`` class. To prevent
@@ -963,15 +963,15 @@ this from happening, use a ``view_defaults`` decorator without any arguments on
the subclass:
.. code-block:: python
- :linenos:
+ :linenos:
- @view_defaults(route_name='rest')
- class Foo(object):
- pass
+ @view_defaults(route_name='rest')
+ class Foo(object):
+ pass
- @view_defaults()
- class Bar(Foo):
- pass
+ @view_defaults()
+ class Bar(Foo):
+ pass
The ``view_defaults`` decorator only works as a class decorator; using it
against a function or a method will produce nonsensical results.
@@ -993,13 +993,13 @@ called. Here's an example of specifying a permission in a view configuration
using :meth:`~pyramid.config.Configurator.add_view`:
.. code-block:: python
- :linenos:
+ :linenos:
- # config is an instance of pyramid.config.Configurator
+ # config is an instance of pyramid.config.Configurator
- config.add_route('add', '/add.html', factory='mypackage.Blog')
- config.add_view('myproject.views.add_entry', route_name='add',
- permission='add')
+ config.add_route('add', '/add.html', factory='mypackage.Blog')
+ config.add_view('myproject.views.add_entry', route_name='add',
+ permission='add')
When an :term:`authorization policy` is enabled, this view will be protected
with the ``add`` permission. The view will *not be called* if the user does
@@ -1055,14 +1055,14 @@ However, the view itself prevents caching from taking place unless there's a
.. code-block:: python
- from pyramid.view import view_config
+ from pyramid.view import view_config
- @view_config(http_cache=3600)
- def view(request):
- response = Response()
- if 'should_cache' not in request.params:
- response.cache_control.prevent_auto = True
- return response
+ @view_config(http_cache=3600)
+ def view(request):
+ response = Response()
+ if 'should_cache' not in request.params:
+ response.cache_control.prevent_auto = True
+ return response
Note that the ``http_cache`` machinery will overwrite or add to caching headers
you set within the view itself, unless you use ``prevent_auto``.
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index 11d9f778a..a53063f78 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -58,12 +58,12 @@ accepts a single argument named ``request``, and which returns a
implemented as a function:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- def hello_world(request):
- return Response('Hello world!')
+ def hello_world(request):
+ return Response('Hello world!')
.. index::
single: view calling convention
@@ -90,16 +90,16 @@ parameters. Views defined as classes must have the following traits.
For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- class MyView(object):
- def __init__(self, request):
- self.request = request
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
- def __call__(self):
- return Response('hello')
+ def __call__(self):
+ return Response('hello')
The request object passed to ``__init__`` is the same type of request object
described in :ref:`function_as_view`.
@@ -127,12 +127,12 @@ implements the :term:`Response` interface is to return a
:class:`pyramid.response.Response` object instance directly. For example:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- def view(request):
- return Response('OK')
+ def view(request):
+ return Response('OK')
:app:`Pyramid` provides a range of different "exception" classes which inherit
from :class:`pyramid.response.Response`. For example, an instance of the class
@@ -186,23 +186,23 @@ be raised. This will cause a response to be generated with a ``401
Unauthorized`` status:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPUnauthorized
+ from pyramid.httpexceptions import HTTPUnauthorized
- def aview(request):
- raise HTTPUnauthorized()
+ def aview(request):
+ raise HTTPUnauthorized()
An HTTP exception, instead of being raised, can alternately be *returned* (HTTP
exceptions are also valid response objects):
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPUnauthorized
+ from pyramid.httpexceptions import HTTPUnauthorized
- def aview(request):
- return HTTPUnauthorized()
+ def aview(request):
+ return HTTPUnauthorized()
A shortcut for creating an HTTP exception is the
:func:`pyramid.httpexceptions.exception_response` function. This function
@@ -213,12 +213,12 @@ the :func:`~pyramid.httpexceptions.exception_response` function to construct
and return the same object.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import exception_response
+ from pyramid.httpexceptions import exception_response
- def aview(request):
- raise exception_response(401)
+ def aview(request):
+ raise exception_response(401)
This is the case because ``401`` is the HTTP status code for "HTTP
Unauthorized". Therefore, ``raise exception_response(401)`` is functionally
@@ -277,26 +277,26 @@ For example, given the following exception class in a module named
``helloworld.exceptions``:
.. code-block:: python
- :linenos:
+ :linenos:
- class ValidationFailure(Exception):
- def __init__(self, msg):
- self.msg = msg
+ class ValidationFailure(Exception):
+ def __init__(self, msg):
+ self.msg = msg
You can wire a view callable to be called whenever any of your *other* code
raises a ``helloworld.exceptions.ValidationFailure`` exception:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import exception_view_config
- from helloworld.exceptions import ValidationFailure
+ from pyramid.view import exception_view_config
+ from helloworld.exceptions import ValidationFailure
- @exception_view_config(ValidationFailure)
- def failed_validation(exc, request):
- response = Response('Failed validation: %s' % exc.msg)
- response.status_int = 500
- return response
+ @exception_view_config(ValidationFailure)
+ def failed_validation(exc, request):
+ response = Response('Failed validation: %s' % exc.msg)
+ response.status_int = 500
+ return response
Assuming that a :term:`scan` was run to pick up this view registration, this
view callable will be invoked whenever a
@@ -308,16 +308,16 @@ Other normal view predicates can also be used in combination with an exception
view registration:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.view import view_config
- from helloworld.exceptions import ValidationFailure
+ from pyramid.view import view_config
+ from helloworld.exceptions import ValidationFailure
- @exception_view_config(ValidationFailure, route_name='home')
- def failed_validation(exc, request):
- response = Response('Failed validation: %s' % exc.msg)
- response.status_int = 500
- return response
+ @exception_view_config(ValidationFailure, route_name='home')
+ def failed_validation(exc, request):
+ response = Response('Failed validation: %s' % exc.msg)
+ response.status_int = 500
+ return response
The above exception view names the ``route_name`` of ``home``, meaning that it
will only be called when the route matched has a name of ``home``. You can
@@ -374,22 +374,22 @@ instance of this class will cause the client to receive a "302 Found" response.
To do so, you can *return* a :class:`pyramid.httpexceptions.HTTPFound` instance.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPFound
+ from pyramid.httpexceptions import HTTPFound
- def myview(request):
- return HTTPFound(location='http://example.com')
+ def myview(request):
+ return HTTPFound(location='http://example.com')
Alternately, you can *raise* an HTTPFound exception instead of returning one.
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.httpexceptions import HTTPFound
+ from pyramid.httpexceptions import HTTPFound
- def myview(request):
- raise HTTPFound(location='http://example.com')
+ def myview(request):
+ raise HTTPFound(location='http://example.com')
When the instance is raised, it is caught by the default :term:`exception
response` handler and turned into a response.
@@ -439,22 +439,22 @@ As an example, let's assume that the following form page is served up to a
browser client, and its ``action`` points at some :app:`Pyramid` view code:
.. code-block:: xml
- :linenos:
-
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- </head>
- <form method="POST" action="myview">
- <div>
- <input type="text" name="firstname"/>
- </div>
- <div>
- <input type="text" name="lastname"/>
- </div>
- <input type="submit" value="Submit"/>
- </form>
- </html>
+ :linenos:
+
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ </head>
+ <form method="POST" action="myview">
+ <div>
+ <input type="text" name="firstname"/>
+ </div>
+ <div>
+ <input type="text" name="lastname"/>
+ </div>
+ <input type="submit" value="Submit"/>
+ </form>
+ </html>
The ``myview`` view code in the :app:`Pyramid` application *must* expect that
the values returned by ``request.params`` will be of type ``unicode``, as
@@ -462,23 +462,23 @@ opposed to type ``str``. The following will work to accept a form post from the
above form:
.. code-block:: python
- :linenos:
+ :linenos:
- def myview(request):
- firstname = request.params['firstname']
- lastname = request.params['lastname']
+ def myview(request):
+ firstname = request.params['firstname']
+ lastname = request.params['lastname']
But the following ``myview`` view code *may not* work, as it tries to decode
already-decoded (``unicode``) values obtained from ``request.params``:
.. code-block:: python
- :linenos:
+ :linenos:
- def myview(request):
- # the .decode('utf-8') will break below if there are any high-order
- # characters in the firstname or lastname
- firstname = request.params['firstname'].decode('utf-8')
- lastname = request.params['lastname'].decode('utf-8')
+ def myview(request):
+ # the .decode('utf-8') will break below if there are any high-order
+ # characters in the firstname or lastname
+ firstname = request.params['firstname'].decode('utf-8')
+ lastname = request.params['lastname'].decode('utf-8')
For implicit decoding to work reliably, you should ensure that every form you
render that posts to a :app:`Pyramid` view explicitly defines a charset
@@ -553,30 +553,30 @@ The following types work as view callables in this style:
and a ``__call__`` method which accepts no arguments, e.g.:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- class view(object):
- def __init__(self, context, request):
- self.context = context
- self.request = request
+ class view(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
- def __call__(self):
- return Response('OK')
+ def __call__(self):
+ return Response('OK')
#. Arbitrary callables that have a ``__call__`` method that accepts ``context,
request``, e.g.:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
+ from pyramid.response import Response
- class View(object):
- def __call__(self, context, request):
- return Response('OK')
- view = View() # this is the view callable
+ class View(object):
+ def __call__(self, context, request):
+ return Response('OK')
+ view = View() # this is the view callable
This style of calling convention is most useful for :term:`traversal` based
applications, where the context object is frequently used within the view
diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst
index ae76d3500..e78c524ff 100644
--- a/docs/narr/webob.rst
+++ b/docs/narr/webob.rst
@@ -252,8 +252,8 @@ Using ``request.json_body`` is equivalent to:
.. code-block:: python
- from json import loads
- loads(request.body, encoding=request.charset)
+ from json import loads
+ loads(request.body, encoding=request.charset)
Here's how to construct an AJAX request in JavaScript using :term:`jQuery` that
allows you to use the ``request.json_body`` attribute when the request is sent
@@ -321,19 +321,19 @@ session to be removed after each request. Put the following in the
``mypackage.__init__`` module:
.. code-block:: python
- :linenos:
+ :linenos:
- from mypackage.models import DBSession
+ from mypackage.models import DBSession
- from pyramid.events import subscriber
- from pyramid.events import NewRequest
+ from pyramid.events import subscriber
+ from pyramid.events import NewRequest
- def cleanup_callback(request):
- DBSession.remove()
+ def cleanup_callback(request):
+ DBSession.remove()
- @subscriber(NewRequest)
- def add_cleanup_callback(event):
- event.request.add_finished_callback(cleanup_callback)
+ @subscriber(NewRequest)
+ def add_cleanup_callback(event):
+ event.request.add_finished_callback(cleanup_callback)
Registering the ``cleanup_callback`` finished callback at the start of a
request (by causing the ``add_cleanup_callback`` to receive a
@@ -450,10 +450,10 @@ attribute of the response can be passed in as a keyword argument to the class,
e.g.:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.response import Response
- response = Response(body='hello world!', content_type='text/plain')
+ from pyramid.response import Response
+ response = Response(body='hello world!', content_type='text/plain')
The status defaults to ``'200 OK'``.
diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst
index 784886563..221617fa7 100644
--- a/docs/narr/zca.rst
+++ b/docs/narr/zca.rst
@@ -21,11 +21,11 @@ lookup using the :func:`zope.component.getUtility` global API as it might
appear in a traditional Zope application:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.interfaces import ISettings
- from zope.component import getUtility
- settings = getUtility(ISettings)
+ from pyramid.interfaces import ISettings
+ from zope.component import getUtility
+ settings = getUtility(ISettings)
After this code runs, ``settings`` will be a Python dictionary. But it's
unlikely that any "civilian" will be able to figure this out just by reading
@@ -106,7 +106,7 @@ equivalent to ``zope.component.getUtility(IFoo)``:
.. code-block:: python
- registry.getUtility(IFoo)
+ registry.getUtility(IFoo)
The full method API is documented in the ``zope.component`` package, but it
largely mirrors the "global" API almost exactly.
@@ -139,14 +139,14 @@ Enabling the ZCA global API by using ``hook_zca``
Consider the following bit of idiomatic :app:`Pyramid` startup code:
.. code-block:: python
- :linenos:
+ :linenos:
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def app(global_settings, **settings):
- config = Configurator(settings=settings)
- config.include('some.other.package')
- return config.make_wsgi_app()
+ def app(global_settings, **settings):
+ config = Configurator(settings=settings)
+ config.include('some.other.package')
+ return config.make_wsgi_app()
When the ``app`` function above is run, a :term:`Configurator` is constructed.
When the configurator is created, it creates a *new* :term:`application
@@ -171,27 +171,27 @@ registry, you need to call :meth:`~pyramid.config.Configurator.hook_zca` within
your setup code. For example:
.. code-block:: python
- :linenos:
- :emphasize-lines: 5
+ :linenos:
+ :emphasize-lines: 5
- from pyramid.config import Configurator
+ from pyramid.config import Configurator
- def app(global_settings, **settings):
- config = Configurator(settings=settings)
- config.hook_zca()
- config.include('some.other.application')
- return config.make_wsgi_app()
+ def app(global_settings, **settings):
+ config = Configurator(settings=settings)
+ config.hook_zca()
+ config.include('some.other.application')
+ return config.make_wsgi_app()
We've added a line to our original startup code, line number 5, which calls
``config.hook_zca()``. The effect of this line under the hood is that an
analogue of the following code is executed:
.. code-block:: python
- :linenos:
+ :linenos:
- from zope.component import getSiteManager
- from pyramid.threadlocal import get_current_registry
- getSiteManager.sethook(get_current_registry)
+ from zope.component import getSiteManager
+ from pyramid.threadlocal import get_current_registry
+ getSiteManager.sethook(get_current_registry)
This causes the ZCA global API to start using the :app:`Pyramid` application
registry in threads which are running a :app:`Pyramid` request.
@@ -217,18 +217,18 @@ You can tell your :app:`Pyramid` application to use the ZCA global registry at
startup time instead of constructing a new one:
.. code-block:: python
- :linenos:
- :emphasize-lines: 5-7
-
- from zope.component import getGlobalSiteManager
- from pyramid.config import Configurator
-
- def app(global_settings, **settings):
- globalreg = getGlobalSiteManager()
- config = Configurator(registry=globalreg)
- config.setup_registry(settings=settings)
- config.include('some.other.application')
- return config.make_wsgi_app()
+ :linenos:
+ :emphasize-lines: 5-7
+
+ from zope.component import getGlobalSiteManager
+ from pyramid.config import Configurator
+
+ def app(global_settings, **settings):
+ globalreg = getGlobalSiteManager()
+ config = Configurator(registry=globalreg)
+ config.setup_registry(settings=settings)
+ config.include('some.other.application')
+ return config.make_wsgi_app()
Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves the global
ZCA component registry. Line 6 creates a :term:`Configurator`, passing the
diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst
index db0da3282..6c240da1a 100644
--- a/docs/quick_tour.rst
+++ b/docs/quick_tour.rst
@@ -55,7 +55,7 @@ For Windows:
Of course Pyramid runs fine on Python 2.7+, as do the examples in this *Quick
Tour*. We're showing Python 3 for simplicity. (Pyramid had production support
for Python 3 in October 2011.) Also for simplicity, the remaining examples will
-show only UNIX commands.
+show only Unix commands.
.. seealso:: See also:
:ref:`Quick Tutorial section on Requirements <qtut_requirements>`,
@@ -133,7 +133,7 @@ included in the body of the response:
.. code-block:: text
- URL http://localhost:6543/?name=alice with name: alice
+ URL http://localhost:6543/?name=alice with name: alice
Finally we set the response's content type, and return the Response.
@@ -263,7 +263,7 @@ Chameleon as a :term:`renderer` in our Pyramid application:
.. code-block:: bash
- $ $VENV/bin/pip install pyramid_chameleon
+ $VENV/bin/pip install pyramid_chameleon
With the package installed, we can include the template bindings into our
configuration in ``app.py``:
@@ -309,7 +309,7 @@ Jinja2 as a :term:`renderer` in our Pyramid applications:
.. code-block:: bash
- $ $VENV/bin/pip install pyramid_jinja2
+ $VENV/bin/pip install pyramid_jinja2
With the package installed, we can include the template bindings into our
configuration:
@@ -504,13 +504,13 @@ First you'll need to install cookiecutter.
.. code-block:: bash
- $ $VENV/bin/pip install cookiecutter
+ $VENV/bin/pip install cookiecutter
Let's use the cookiecutter ``pyramid-cookiecutter-starter`` to create a starter Pyramid project in the current directory, entering values at the prompts as shown below for the following command.
.. code-block:: bash
- $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
+ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -531,15 +531,15 @@ We then run through the following commands.
.. code-block:: bash
# Change directory into your newly created project.
- $ cd hello_world
+ cd hello_world
# Create a new virtual environment...
- $ python3 -m venv env
+ python3 -m venv env
# ...where we upgrade packaging tools...
- $ env/bin/pip install --upgrade pip setuptools
+ env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project and its testing requirements.
- $ env/bin/pip install -e ".[testing]"
+ env/bin/pip install -e ".[testing]"
# Reset our environment variable for a new virtual environment.
- $ export VENV=~/hello_world/env
+ export VENV=~/hello_world/env
We are moving in the direction of a full-featured Pyramid project, with a
proper setup for Python standards (packaging) and Pyramid configuration. This
@@ -547,7 +547,7 @@ includes a new way of running your application:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini
+ $VENV/bin/pserve development.ini
Let's look at ``pserve`` and configuration in more depth.
@@ -574,7 +574,7 @@ the server when they change:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
The ``pserve`` command has a number of other options and operations. Most of
the work, though, comes from your project's wiring, as expressed in the
@@ -654,7 +654,7 @@ It was installed when you previously ran:
.. code-block:: bash
- $ $VENV/bin/pip install -e ".[testing]"
+ $VENV/bin/pip install -e ".[testing]"
The ``pyramid_debugtoolbar`` package is a Pyramid add-on, which means we need
to include its configuration into our web application. The cookiecutter already took care of this for us in its ``development.ini`` using the ``pyramid.includes`` facility:
@@ -701,7 +701,7 @@ We already installed the test requirements when we ran the command ``$VENV/bin/p
.. code-block:: bash
- $ $VENV/bin/py.test --cov --cov-report=term-missing
+ $VENV/bin/py.test --cov --cov-report=term-missing
This yields the following output.
@@ -857,8 +857,8 @@ Pyramid and SQLAlchemy are great friends. That friendship includes a cookiecutte
.. code-block:: bash
- $ cd ~
- $ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master
+ cd ~
+ env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -874,15 +874,15 @@ We then run through the following commands as before.
.. code-block:: bash
# Change directory into your newly created project.
- $ cd sqla_demo
+ cd sqla_demo
# Create a new virtual environment...
- $ python3 -m venv env
+ python3 -m venv env
# ...where we upgrade packaging tools...
- $ env/bin/pip install --upgrade pip setuptools
+ env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project and its testing requirements.
- $ env/bin/pip install -e ".[testing]"
+ env/bin/pip install -e ".[testing]"
# Reset our environment variable for a new virtual environment.
- $ export VENV=~/sqla_demo/env
+ export VENV=~/sqla_demo/env
We now have a working sample SQLAlchemy application with all dependencies
installed. The sample project provides a console script to initialize a SQLite
@@ -890,8 +890,8 @@ database with tables. Let's run it, then start the application:
.. code-block:: bash
- $ $VENV/bin/initialize_sqla_demo_db development.ini
- $ $VENV/bin/pserve development.ini
+ $VENV/bin/initialize_sqla_demo_db development.ini
+ $VENV/bin/pserve development.ini
The ORM eases the mapping of database structures into a programming language.
SQLAlchemy uses "models" for this mapping. The cookiecutter generated a sample
diff --git a/docs/quick_tutorial/authentication.rst b/docs/quick_tutorial/authentication.rst
index 529f51ddd..eb9b6b395 100644
--- a/docs/quick_tutorial/authentication.rst
+++ b/docs/quick_tutorial/authentication.rst
@@ -33,7 +33,7 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes authentication; cd authentication
+ cd ..; cp -r view_classes authentication; cd authentication
#. Add ``bcrypt`` as a dependency in ``authentication/setup.py``:
@@ -46,7 +46,7 @@ Steps
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
#. Put the security hash in the ``authentication/development.ini``
configuration file as ``tutorial.secret`` instead of putting it in the code:
@@ -88,7 +88,7 @@ Steps
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in a browser.
diff --git a/docs/quick_tutorial/authorization.rst b/docs/quick_tutorial/authorization.rst
index 58c1d2582..e80f88c51 100644
--- a/docs/quick_tutorial/authorization.rst
+++ b/docs/quick_tutorial/authorization.rst
@@ -41,31 +41,31 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r authentication authorization; cd authorization
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r authentication authorization; cd authorization
+ $VENV/bin/pip install -e .
#. Start by changing ``authorization/tutorial/__init__.py`` to specify a root
factory to the :term:`configurator`:
.. literalinclude:: authorization/tutorial/__init__.py
- :linenos:
+ :linenos:
#. That means we need to implement ``authorization/tutorial/resources.py``:
.. literalinclude:: authorization/tutorial/resources.py
- :linenos:
+ :linenos:
#. Change ``authorization/tutorial/views.py`` to require the ``edit``
permission on the ``hello`` view and implement the forbidden view:
.. literalinclude:: authorization/tutorial/views.py
- :linenos:
+ :linenos:
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in a browser.
diff --git a/docs/quick_tutorial/cookiecutters.rst b/docs/quick_tutorial/cookiecutters.rst
index f8568206d..045808884 100644
--- a/docs/quick_tutorial/cookiecutters.rst
+++ b/docs/quick_tutorial/cookiecutters.rst
@@ -28,7 +28,7 @@ Steps
.. code-block:: bash
- $ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
+ $VENV/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -49,20 +49,20 @@ Steps
.. code-block:: bash
# Change directory into your newly created project.
- $ cd cc_starter
+ cd cc_starter
# Create a new virtual environment...
- $ python3 -m venv env
+ python3 -m venv env
# ...where we upgrade packaging tools...
- $ env/bin/pip install --upgrade pip setuptools
+ env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project.
- $ env/bin/pip install -e .
+ env/bin/pip install -e .
#. Start up the application by pointing :app:`Pyramid`'s ``pserve`` command at the
project's (generated) configuration file:
.. code-block:: bash
- $ env/bin/pserve development.ini --reload
+ env/bin/pserve development.ini --reload
On start up, ``pserve`` logs some output:
diff --git a/docs/quick_tutorial/databases.rst b/docs/quick_tutorial/databases.rst
index 87f2703c7..7d10f2470 100644
--- a/docs/quick_tutorial/databases.rst
+++ b/docs/quick_tutorial/databases.rst
@@ -45,7 +45,7 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r forms databases; cd databases
+ cd ..; cp -r forms databases; cd databases
#. We need to add some dependencies in ``databases/setup.py`` as well as an
"entry point" for the command-line script:
@@ -62,85 +62,85 @@ Steps
new pieces:
.. literalinclude:: databases/development.ini
- :language: ini
+ :language: ini
#. This engine configuration now needs to be read into the application through
changes in ``databases/tutorial/__init__.py``:
.. literalinclude:: databases/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Make a command-line script at ``databases/tutorial/initialize_db.py`` to
initialize the database:
.. literalinclude:: databases/tutorial/initialize_db.py
- :linenos:
+ :linenos:
#. Since ``setup.py`` changed, we now run it:
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
#. The script references some models in ``databases/tutorial/models.py``:
.. literalinclude:: databases/tutorial/models.py
- :linenos:
+ :linenos:
#. Let's run this console script, thus producing our database and table:
.. code-block:: bash
- $ $VENV/bin/initialize_tutorial_db development.ini
-
- 2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
- 2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
- 2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
- 2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
- 2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("wikipages")
- 2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
- 2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.base.Engine][MainThread]
- CREATE TABLE wikipages (
- uid INTEGER NOT NULL,
- title TEXT,
- body TEXT,
- PRIMARY KEY (uid),
- UNIQUE (title)
- )
-
-
- 2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
- 2016-04-16 13:01:33,059 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT
- 2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit)
- 2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO wikipages (title, body) VALUES (?, ?)
- 2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.base.Engine][MainThread] ('Root', '<p>Root</p>')
- 2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT
+ $VENV/bin/initialize_tutorial_db development.ini
+
+ 2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
+ 2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
+ 2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("wikipages")
+ 2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ CREATE TABLE wikipages (
+ uid INTEGER NOT NULL,
+ title TEXT,
+ body TEXT,
+ PRIMARY KEY (uid),
+ UNIQUE (title)
+ )
+
+
+ 2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2016-04-16 13:01:33,059 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT
+ 2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit)
+ 2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO wikipages (title, body) VALUES (?, ?)
+ 2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.base.Engine][MainThread] ('Root', '<p>Root</p>')
+ 2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT
#. With our data now driven by SQLAlchemy queries, we need to update our
``databases/tutorial/views.py``:
.. literalinclude:: databases/tutorial/views.py
- :linenos:
+ :linenos:
#. Our tests in ``databases/tutorial/tests.py`` changed to include SQLAlchemy
bootstrapping:
.. literalinclude:: databases/tutorial/tests.py
- :linenos:
+ :linenos:
#. Run the tests in your package using ``py.test``:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ..
- 2 passed in 1.41 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ..
+ 2 passed in 1.41 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in a browser.
diff --git a/docs/quick_tutorial/debugtoolbar.rst b/docs/quick_tutorial/debugtoolbar.rst
index 4402fcdbd..b49dd1f97 100644
--- a/docs/quick_tutorial/debugtoolbar.rst
+++ b/docs/quick_tutorial/debugtoolbar.rst
@@ -37,22 +37,22 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r ini debugtoolbar; cd debugtoolbar
- $ $VENV/bin/pip install -e .
- $ $VENV/bin/pip install pyramid_debugtoolbar
+ cd ..; cp -r ini debugtoolbar; cd debugtoolbar
+ $VENV/bin/pip install -e .
+ $VENV/bin/pip install pyramid_debugtoolbar
#. Our ``debugtoolbar/development.ini`` gets a configuration entry for
``pyramid.includes``:
.. literalinclude:: debugtoolbar/development.ini
- :language: ini
- :linenos:
+ :language: ini
+ :linenos:
#. Run the WSGI application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in your browser. See the handy
toolbar on the right.
@@ -100,15 +100,15 @@ Extra credit
.. code-block:: python
- def hello_world(request):
- return Response('<body><h1>Hello World!</h1></body>')
+ def hello_world(request):
+ return Response('<body><h1>Hello World!</h1></body>')
to:
.. code-block:: python
- def hello_world(request):
- return xResponse('<body><h1>Hello World!</h1></body>')
+ def hello_world(request):
+ return xResponse('<body><h1>Hello World!</h1></body>')
Save, and visit http://localhost:6543/ again. Notice the nice traceback
display. On the lowest line, click the "screen" icon to the right, and try
diff --git a/docs/quick_tutorial/forms.rst b/docs/quick_tutorial/forms.rst
index 45eb05a8f..be745764b 100644
--- a/docs/quick_tutorial/forms.rst
+++ b/docs/quick_tutorial/forms.rst
@@ -35,71 +35,71 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes forms; cd forms
+ cd ..; cp -r view_classes forms; cd forms
#. Let's edit ``forms/setup.py`` to declare a dependency on Deform (which then
pulls in Colander as a dependency:
.. literalinclude:: forms/setup.py
- :emphasize-lines: 4
- :linenos:
+ :emphasize-lines: 4
+ :linenos:
#. We can now install our project in development mode:
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
#. Register a static view in ``forms/tutorial/__init__.py`` for Deform's CSS,
JavaScript, etc., as well as our demo wiki page's views:
.. literalinclude:: forms/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Implement the new views, as well as the form schemas and some dummy data, in
``forms/tutorial/views.py``:
.. literalinclude:: forms/tutorial/views.py
- :linenos:
+ :linenos:
#. A template for the top of the "wiki" in ``forms/tutorial/wiki_view.pt``:
.. literalinclude:: forms/tutorial/wiki_view.pt
- :language: html
- :linenos:
+ :language: html
+ :linenos:
#. Another template for adding/editing in
``forms/tutorial/wikipage_addedit.pt``:
.. literalinclude:: forms/tutorial/wikipage_addedit.pt
- :language: html
- :linenos:
+ :language: html
+ :linenos:
#. Add a template at ``forms/tutorial/wikipage_view.pt`` for viewing a wiki
page:
.. literalinclude:: forms/tutorial/wikipage_view.pt
- :language: html
- :linenos:
+ :language: html
+ :linenos:
#. Our tests in ``forms/tutorial/tests.py`` don't run, so let's modify them:
.. literalinclude:: forms/tutorial/tests.py
- :linenos:
+ :linenos:
#. Run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ..
- 2 passed in 0.45 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ..
+ 2 passed in 0.45 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in a browser.
diff --git a/docs/quick_tutorial/functional_testing.rst b/docs/quick_tutorial/functional_testing.rst
index 518e3d67d..fa56b4589 100644
--- a/docs/quick_tutorial/functional_testing.rst
+++ b/docs/quick_tutorial/functional_testing.rst
@@ -36,15 +36,15 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r unit_testing functional_testing; cd functional_testing
- $ $VENV/bin/pip install -e .
- $ $VENV/bin/pip install webtest
+ cd ..; cp -r unit_testing functional_testing; cd functional_testing
+ $VENV/bin/pip install -e .
+ $VENV/bin/pip install webtest
#. Let's extend ``functional_testing/tutorial/tests.py`` to include a
functional test:
.. literalinclude:: functional_testing/tutorial/tests.py
- :linenos:
+ :linenos:
Be sure this file is not executable, or ``pytest`` may not include your
tests.
@@ -53,9 +53,9 @@ Steps
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ..
- 2 passed in 0.25 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ..
+ 2 passed in 0.25 seconds
Analysis
diff --git a/docs/quick_tutorial/hello_world.rst b/docs/quick_tutorial/hello_world.rst
index 94242f1f4..161f07ac8 100644
--- a/docs/quick_tutorial/hello_world.rst
+++ b/docs/quick_tutorial/hello_world.rst
@@ -49,18 +49,18 @@ Steps
.. code-block:: bash
- $ cd ~/projects/quick_tutorial; mkdir hello_world; cd hello_world
+ cd ~/projects/quick_tutorial; mkdir hello_world; cd hello_world
#. Copy the following into ``hello_world/app.py``:
.. literalinclude:: hello_world/app.py
- :linenos:
+ :linenos:
#. Run the application:
.. code-block:: bash
- $ $VENV/bin/python app.py
+ $VENV/bin/python app.py
#. Open http://localhost:6543/ in your browser.
@@ -95,13 +95,13 @@ Extra credit
.. code-block:: python
- print('Incoming request')
+ print('Incoming request')
...instead of:
.. code-block:: python
- print 'Incoming request'
+ print 'Incoming request'
#. What happens if you return a string of HTML? A sequence of integers?
diff --git a/docs/quick_tutorial/ini.rst b/docs/quick_tutorial/ini.rst
index e4f30405f..ce92914fe 100644
--- a/docs/quick_tutorial/ini.rst
+++ b/docs/quick_tutorial/ini.rst
@@ -39,44 +39,44 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r package ini; cd ini
+ cd ..; cp -r package ini; cd ini
#. Our ``ini/setup.py`` needs a setuptools "entry point" in the ``setup()``
function:
.. literalinclude:: ini/setup.py
- :linenos:
+ :linenos:
#. We can now install our project, thus generating (or re-generating) an "egg"
at ``ini/tutorial.egg-info``:
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
#. Let's make a file ``ini/development.ini`` for our configuration:
.. literalinclude:: ini/development.ini
- :language: ini
- :linenos:
+ :language: ini
+ :linenos:
#. We can refactor our startup code from the previous step's ``app.py`` into
``ini/tutorial/__init__.py``:
.. literalinclude:: ini/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Now that ``ini/tutorial/app.py`` isn't used, let's remove it:
.. code-block:: bash
- $ rm tutorial/app.py
+ rm tutorial/app.py
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/.
diff --git a/docs/quick_tutorial/jinja2.rst b/docs/quick_tutorial/jinja2.rst
index 4faa81fc4..87122a374 100644
--- a/docs/quick_tutorial/jinja2.rst
+++ b/docs/quick_tutorial/jinja2.rst
@@ -27,38 +27,38 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes jinja2; cd jinja2
- $ $VENV/bin/pip install -e .
- $ $VENV/bin/pip install pyramid_jinja2
+ cd ..; cp -r view_classes jinja2; cd jinja2
+ $VENV/bin/pip install -e .
+ $VENV/bin/pip install pyramid_jinja2
#. We need to include ``pyramid_jinja2`` in ``jinja2/tutorial/__init__.py``:
.. literalinclude:: jinja2/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Our ``jinja2/tutorial/views.py`` simply changes its ``renderer``:
.. literalinclude:: jinja2/tutorial/views.py
- :linenos:
+ :linenos:
#. Add ``jinja2/tutorial/home.jinja2`` as a template:
.. literalinclude:: jinja2/tutorial/home.jinja2
- :language: html
+ :language: html
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 4 passed in 0.40 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 4 passed in 0.40 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in your browser.
diff --git a/docs/quick_tutorial/json.rst b/docs/quick_tutorial/json.rst
index ff153d2b5..98283424c 100644
--- a/docs/quick_tutorial/json.rst
+++ b/docs/quick_tutorial/json.rst
@@ -31,32 +31,32 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes json; cd json
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r view_classes json; cd json
+ $VENV/bin/pip install -e .
#. We add a new route for ``hello_json`` in ``json/tutorial/__init__.py``:
.. literalinclude:: json/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Rather than implement a new view, we will "stack" another decorator on the
``hello`` view in ``views.py``:
.. literalinclude:: json/tutorial/views.py
- :linenos:
+ :linenos:
#. We need a new functional test at the end of ``json/tutorial/tests.py``:
.. literalinclude:: json/tutorial/tests.py
- :linenos:
+ :linenos:
#. Run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- .....
- 5 passed in 0.47 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ .....
+ 5 passed in 0.47 seconds
#. Run your Pyramid application with:
diff --git a/docs/quick_tutorial/logging.rst b/docs/quick_tutorial/logging.rst
index 0a530e91f..ccbb7970f 100644
--- a/docs/quick_tutorial/logging.rst
+++ b/docs/quick_tutorial/logging.rst
@@ -36,13 +36,13 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes logging; cd logging
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r view_classes logging; cd logging
+ $VENV/bin/pip install -e .
#. Extend ``logging/tutorial/views.py`` to log a message:
.. literalinclude:: logging/tutorial/views.py
- :linenos:
+ :linenos:
#. Finally let's edit ``development.ini`` configuration file to enable logging
for our Pyramid application:
@@ -54,15 +54,15 @@ Steps
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 4 passed in 0.41 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 4 passed in 0.41 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.
Note, both in the console and in the debug toolbar, the message that you
diff --git a/docs/quick_tutorial/more_view_classes.rst b/docs/quick_tutorial/more_view_classes.rst
index db1c68168..15452e9ae 100644
--- a/docs/quick_tutorial/more_view_classes.rst
+++ b/docs/quick_tutorial/more_view_classes.rst
@@ -57,63 +57,63 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r templating more_view_classes; cd more_view_classes
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r templating more_view_classes; cd more_view_classes
+ $VENV/bin/pip install -e .
#. Our route in ``more_view_classes/tutorial/__init__.py`` needs some
replacement patterns:
.. literalinclude:: more_view_classes/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Our ``more_view_classes/tutorial/views.py`` now has a view class with
several views:
.. literalinclude:: more_view_classes/tutorial/views.py
- :linenos:
+ :linenos:
#. Our primary view needs a template at ``more_view_classes/tutorial/home.pt``:
.. literalinclude:: more_view_classes/tutorial/home.pt
- :language: html
+ :language: html
#. Ditto for our other view from the previous section at
``more_view_classes/tutorial/hello.pt``:
.. literalinclude:: more_view_classes/tutorial/hello.pt
- :language: html
+ :language: html
#. We have an edit view that also needs a template at
``more_view_classes/tutorial/edit.pt``:
.. literalinclude:: more_view_classes/tutorial/edit.pt
- :language: html
+ :language: html
#. And finally the delete view's template at
``more_view_classes/tutorial/delete.pt``:
.. literalinclude:: more_view_classes/tutorial/delete.pt
- :language: html
+ :language: html
#. Our tests in ``more_view_classes/tutorial/tests.py`` fail, so let's modify
them:
.. literalinclude:: more_view_classes/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ..
- 2 passed in 0.40 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ..
+ 2 passed in 0.40 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/howdy/jane/doe in your browser. Click the
``Save`` and ``Delete`` buttons, and watch the output in the console window.
@@ -161,13 +161,13 @@ previously hardcoded the URLs, such as:
.. code-block:: html
- <a href="/howdy/jane/doe">Howdy</a>
+ <a href="/howdy/jane/doe">Howdy</a>
In ``home.pt`` we switched to:
.. code-block:: xml
- <a href="${request.route_url('hello', first='jane',
+ <a href="${request.route_url('hello', first='jane',
last='doe')}">form</a>
Pyramid has rich facilities to help generate URLs in a flexible, non-error
diff --git a/docs/quick_tutorial/package.rst b/docs/quick_tutorial/package.rst
index 34bc0f7eb..ae82fef03 100644
--- a/docs/quick_tutorial/package.rst
+++ b/docs/quick_tutorial/package.rst
@@ -53,7 +53,7 @@ Steps
.. code-block:: bash
- $ cd ..; mkdir package; cd package
+ cd ..; mkdir package; cd package
#. In ``package/setup.py``, enter the following:
@@ -64,8 +64,8 @@ Steps
.. code-block:: bash
- $ $VENV/bin/pip install -e .
- $ mkdir tutorial
+ $VENV/bin/pip install -e .
+ mkdir tutorial
#. Enter the following into ``package/tutorial/__init__.py``:
@@ -79,7 +79,7 @@ Steps
.. code-block:: bash
- $ $VENV/bin/python tutorial/app.py
+ $VENV/bin/python tutorial/app.py
#. Open http://localhost:6543/ in your browser.
diff --git a/docs/quick_tutorial/request_response.rst b/docs/quick_tutorial/request_response.rst
index ece8cdd6f..098753820 100644
--- a/docs/quick_tutorial/request_response.rst
+++ b/docs/quick_tutorial/request_response.rst
@@ -39,37 +39,37 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes request_response; cd request_response
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r view_classes request_response; cd request_response
+ $VENV/bin/pip install -e .
#. Simplify the routes in ``request_response/tutorial/__init__.py``:
.. literalinclude:: request_response/tutorial/__init__.py
- :linenos:
+ :linenos:
#. We only need one view in ``request_response/tutorial/views.py``:
.. literalinclude:: request_response/tutorial/views.py
- :linenos:
+ :linenos:
#. Update the tests in ``request_response/tutorial/tests.py``:
.. literalinclude:: request_response/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- .....
- 5 passed in 0.30 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ .....
+ 5 passed in 0.30 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in your browser. You will be redirected to
http://localhost:6543/plain.
@@ -91,7 +91,7 @@ the body of the response:
.. code-block:: text
- URL http://localhost:6543/plain?name=alice with name: alice
+ URL http://localhost:6543/plain?name=alice with name: alice
Finally, we set the response's content type and body, then return the response.
diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst
index 29f263176..08ea93cb2 100644
--- a/docs/quick_tutorial/requirements.rst
+++ b/docs/quick_tutorial/requirements.rst
@@ -33,7 +33,7 @@ This *Quick Tutorial* is based on:
projects* (a directory with packaging information and *Python packages* of
working code.)
-* **Unix commands**. Commands in this tutorial use UNIX syntax and paths.
+* **Unix commands**. Commands in this tutorial use Unix syntax and paths.
Windows users should adjust commands accordingly.
.. note::
@@ -62,7 +62,7 @@ Install Python 3
See the detailed recommendation for your operating system described under
:ref:`installing_chapter`.
-- :ref:`for-mac-os-x-users`
+- :ref:`for-macos-users`
- :ref:`if-you-don-t-yet-have-a-python-interpreter-unix`
- :ref:`if-you-don-t-yet-have-a-python-interpreter-windows`
@@ -89,23 +89,23 @@ will reside as we proceed through the tutorial:
│ └── app.py
└── setup.py
-For Linux, the commands to do so are as follows:
+For macOS and Linux, the commands to do so are as follows:
.. code-block:: bash
- # Mac and Linux
- $ cd ~
- $ mkdir -p projects/quick_tutorial
- $ cd projects/quick_tutorial
+ # macOS and Linux
+ cd ~
+ mkdir -p projects/quick_tutorial
+ cd projects/quick_tutorial
For Windows:
.. code-block:: doscon
# Windows
- c:\> cd \
- c:\> mkdir projects\quick_tutorial
- c:\> cd projects\quick_tutorial
+ cd \
+ mkdir projects\quick_tutorial
+ cd projects\quick_tutorial
In the above figure, your user home directory is represented by ``~``. In your
home directory, all of your projects are in the ``projects`` directory. This is
@@ -129,13 +129,13 @@ environment`. We set an environment variable to save typing later.
.. code-block:: bash
- # Mac and Linux
- $ export VENV=~/projects/quick_tutorial/env
+ # macOS and Linux
+ export VENV=~/projects/quick_tutorial/env
.. code-block:: doscon
# Windows
- c:\> set VENV=c:\projects\quick_tutorial\env
+ set VENV=c:\projects\quick_tutorial\env
.. _create-a-virtual-environment:
@@ -150,13 +150,13 @@ environment variable.
.. code-block:: bash
- # Mac and Linux
- $ python3 -m venv $VENV
+ # macOS and Linux
+ python3 -m venv $VENV
.. code-block:: doscon
# Windows
- c:\> python -m venv %VENV%
+ python -m venv %VENV%
.. seealso:: See also Python 3's :mod:`venv module <python:venv>` and Python
2's `virtualenv <https://virtualenv.pypa.io/en/latest/>`_ package.
@@ -171,13 +171,13 @@ time of its release.
.. code-block:: bash
- # Mac and Linux
- $ $VENV/bin/pip install --upgrade pip setuptools
+ # macOS and Linux
+ $VENV/bin/pip install --upgrade pip setuptools
.. code-block:: doscon
# Windows
- c:\> %VENV%\Scripts\pip install --upgrade pip setuptools
+ %VENV%\Scripts\pip install --upgrade pip setuptools
.. seealso:: See also :ref:`Why use $VENV/bin/pip instead of source
bin/activate, then pip <venv-bin-pip-vs-source-bin-activate>`.
@@ -193,11 +193,11 @@ part is pretty easy. We'll also install a WSGI server, Waitress.
.. parsed-literal::
- # Mac and Linux
- $ $VENV/bin/pip install "pyramid==\ |release|\ " waitress
+ # macOS and Linux
+ $VENV/bin/pip install "pyramid==\ |release|\ " waitress
# Windows
- c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ " waitress
+ %VENV%\\Scripts\\pip install "pyramid==\ |release|\ " waitress
Our Python virtual environment now has the Pyramid software available
as well as the ``waitress`` package.
diff --git a/docs/quick_tutorial/routing.rst b/docs/quick_tutorial/routing.rst
index adbe76a62..0384892b2 100644
--- a/docs/quick_tutorial/routing.rst
+++ b/docs/quick_tutorial/routing.rst
@@ -50,44 +50,44 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes routing; cd routing
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r view_classes routing; cd routing
+ $VENV/bin/pip install -e .
#. Our ``routing/tutorial/__init__.py`` needs a route with a replacement
pattern:
.. literalinclude:: routing/tutorial/__init__.py
- :linenos:
+ :linenos:
#. We just need one view in ``routing/tutorial/views.py``:
.. literalinclude:: routing/tutorial/views.py
- :linenos:
+ :linenos:
#. We just need one view in ``routing/tutorial/home.pt``:
.. literalinclude:: routing/tutorial/home.pt
- :language: html
- :linenos:
+ :language: html
+ :linenos:
#. Update ``routing/tutorial/tests.py``:
.. literalinclude:: routing/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ..
- 2 passed in 0.39 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ..
+ 2 passed in 0.39 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/howdy/amy/smith in your browser.
diff --git a/docs/quick_tutorial/sessions.rst b/docs/quick_tutorial/sessions.rst
index df4887a4b..d67a5063a 100644
--- a/docs/quick_tutorial/sessions.rst
+++ b/docs/quick_tutorial/sessions.rst
@@ -36,39 +36,39 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes sessions; cd sessions
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r view_classes sessions; cd sessions
+ $VENV/bin/pip install -e .
#. Our ``sessions/tutorial/__init__.py`` needs a choice of session factory to
get registered with the :term:`configurator`:
.. literalinclude:: sessions/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Our views in ``sessions/tutorial/views.py`` can now use ``request.session``:
.. literalinclude:: sessions/tutorial/views.py
- :linenos:
+ :linenos:
#. The template at ``sessions/tutorial/home.pt`` can display the value:
.. literalinclude:: sessions/tutorial/home.pt
- :language: html
- :linenos:
+ :language: html
+ :linenos:
#. Make sure the tests still pass:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 4 passed in 0.42 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 4 passed in 0.42 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.
As you reload and switch between those URLs, note that the counter increases
diff --git a/docs/quick_tutorial/static_assets.rst b/docs/quick_tutorial/static_assets.rst
index 81a01061a..7a6b5dac3 100644
--- a/docs/quick_tutorial/static_assets.rst
+++ b/docs/quick_tutorial/static_assets.rst
@@ -23,46 +23,46 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r view_classes static_assets; cd static_assets
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r view_classes static_assets; cd static_assets
+ $VENV/bin/pip install -e .
#. We add a call ``config.add_static_view`` in
``static_assets/tutorial/__init__.py``:
.. literalinclude:: static_assets/tutorial/__init__.py
- :linenos:
+ :linenos:
#. We can add a CSS link in the ``<head>`` of our template at
``static_assets/tutorial/home.pt``:
.. literalinclude:: static_assets/tutorial/home.pt
- :language: html
+ :language: html
#. Add a CSS file at ``static_assets/tutorial/static/app.css``:
.. literalinclude:: static_assets/tutorial/static/app.css
- :language: css
+ :language: css
#. We add a functional test that asserts that the newly added static file is delivered:
.. literalinclude:: static_assets/tutorial/tests.py
- :language: python
- :pyobject: TutorialFunctionalTests.test_css
- :lineno-match:
+ :language: python
+ :pyobject: TutorialFunctionalTests.test_css
+ :lineno-match:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 5 passed in 0.50 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 5 passed in 0.50 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ in your browser and note the new font.
@@ -82,7 +82,7 @@ disk? Pyramid gives a helper that provides flexibility on URL generation:
.. code-block:: html
- ${request.static_url('tutorial:static/app.css')}
+ ${request.static_url('tutorial:static/app.css')}
This matches the ``path='tutorial:static'`` in our ``config.add_static_view``
registration. By using ``request.static_url`` to generate the full URL to the
diff --git a/docs/quick_tutorial/templating.rst b/docs/quick_tutorial/templating.rst
index ec6de98f8..3fbef699c 100644
--- a/docs/quick_tutorial/templating.rst
+++ b/docs/quick_tutorial/templating.rst
@@ -47,60 +47,60 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r views templating; cd templating
+ cd ..; cp -r views templating; cd templating
#. This step depends on ``pyramid_chameleon``, so add it as a dependency in
``templating/setup.py``:
.. literalinclude:: templating/setup.py
- :linenos:
+ :linenos:
#. Now we can activate the development-mode distribution:
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
#. We need to connect ``pyramid_chameleon`` as a renderer by making a call in
the setup of ``templating/tutorial/__init__.py``:
.. literalinclude:: templating/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Our ``templating/tutorial/views.py`` no longer has HTML in it:
.. literalinclude:: templating/tutorial/views.py
- :linenos:
+ :linenos:
#. Instead we have ``templating/tutorial/home.pt`` as a template:
.. literalinclude:: templating/tutorial/home.pt
- :language: html
+ :language: html
#. For convenience, change ``templating/development.ini`` to reload templates
automatically with ``pyramid.reload_templates``:
.. literalinclude:: templating/development.ini
- :language: ini
+ :language: ini
#. Our unit tests in ``templating/tutorial/tests.py`` can focus on data:
.. literalinclude:: templating/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 4 passed in 0.46 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 4 passed in 0.46 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.
diff --git a/docs/quick_tutorial/tutorial_approach.rst b/docs/quick_tutorial/tutorial_approach.rst
index 83b229746..7ef28bdb8 100644
--- a/docs/quick_tutorial/tutorial_approach.rst
+++ b/docs/quick_tutorial/tutorial_approach.rst
@@ -40,7 +40,7 @@ For most steps you will copy the previous step's directory to a new directory, a
.. code-block:: bash
- $ cd ..; cp -r package ini; cd ini
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r package ini; cd ini
+ $VENV/bin/pip install -e .
For a few steps, you won't copy the previous step's directory, but you will still need to install your project with ``$VENV/bin/pip install -e .``.
diff --git a/docs/quick_tutorial/unit_testing.rst b/docs/quick_tutorial/unit_testing.rst
index 63fe7c945..09e3ea197 100644
--- a/docs/quick_tutorial/unit_testing.rst
+++ b/docs/quick_tutorial/unit_testing.rst
@@ -48,23 +48,23 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r debugtoolbar unit_testing; cd unit_testing
- $ $VENV/bin/pip install -e .
- $ $VENV/bin/pip install pytest
+ cd ..; cp -r debugtoolbar unit_testing; cd unit_testing
+ $VENV/bin/pip install -e .
+ $VENV/bin/pip install pytest
#. Now we write a simple unit test in ``unit_testing/tutorial/tests.py``:
.. literalinclude:: unit_testing/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- .
- 1 passed in 0.14 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ .
+ 1 passed in 0.14 seconds
Analysis
diff --git a/docs/quick_tutorial/view_classes.rst b/docs/quick_tutorial/view_classes.rst
index 49cdcddcc..fc7ba5125 100644
--- a/docs/quick_tutorial/view_classes.rst
+++ b/docs/quick_tutorial/view_classes.rst
@@ -41,36 +41,35 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r templating view_classes; cd view_classes
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r templating view_classes; cd view_classes
+ $VENV/bin/pip install -e .
#. Our ``view_classes/tutorial/views.py`` now has a view class with our two
views:
.. literalinclude:: view_classes/tutorial/views.py
- :linenos:
+ :linenos:
#. Our unit tests in ``view_classes/tutorial/tests.py`` don't run, so let's
modify them to import the view class, and make an instance before getting a
response:
.. literalinclude:: view_classes/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
-
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 4 passed in 0.34 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 4 passed in 0.34 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser.
diff --git a/docs/quick_tutorial/views.rst b/docs/quick_tutorial/views.rst
index edbe4b2ff..f7fa64719 100644
--- a/docs/quick_tutorial/views.rst
+++ b/docs/quick_tutorial/views.rst
@@ -44,39 +44,39 @@ Steps
.. code-block:: bash
- $ cd ..; cp -r functional_testing views; cd views
- $ $VENV/bin/pip install -e .
+ cd ..; cp -r functional_testing views; cd views
+ $VENV/bin/pip install -e .
#. Our ``views/tutorial/__init__.py`` gets a lot shorter:
.. literalinclude:: views/tutorial/__init__.py
- :linenos:
+ :linenos:
#. Let's add a module ``views/tutorial/views.py`` that is focused on
handling requests and responses:
.. literalinclude:: views/tutorial/views.py
- :linenos:
+ :linenos:
#. Update the tests to cover the two new views:
.. literalinclude:: views/tutorial/tests.py
- :linenos:
+ :linenos:
#. Now run the tests:
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py -q
- ....
- 4 passed in 0.28 seconds
+ $VENV/bin/py.test tutorial/tests.py -q
+ ....
+ 4 passed in 0.28 seconds
#. Run your Pyramid application with:
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
#. Open http://localhost:6543/ and http://localhost:6543/howdy
in your browser.
diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst
index a409284cc..bcedcbe3d 100644
--- a/docs/tutorials/modwsgi/index.rst
+++ b/docs/tutorials/modwsgi/index.rst
@@ -9,7 +9,7 @@ server.
This guide will outline broad steps that can be used to get a :app:`Pyramid`
application running under Apache via ``mod_wsgi``. This particular tutorial
-was developed under Apple's Mac OS X platform (Snow Leopard, on a 32-bit
+was developed under Apple's macOS platform (Snow Leopard, on a 32-bit
Mac), but the instructions should be largely the same for all systems, delta
specific path information for commands and files.
@@ -38,8 +38,8 @@ specific path information for commands and files.
.. code-block:: bash
- $ cd ~
- $ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
+ cd ~
+ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master
If prompted for the first item, accept the default ``yes`` by hitting return.
@@ -63,24 +63,24 @@ specific path information for commands and files.
.. code-block:: bash
- $ cd myproject
- $ python3 -m venv env
+ cd myproject
+ python3 -m venv env
#. Install your :app:`Pyramid` application and its dependencies.
.. code-block:: bash
- $ env/bin/pip install -e .
+ env/bin/pip install -e .
#. Within the project directory (``~/myproject``), create a script
named ``pyramid.wsgi``. Give it these contents:
.. code-block:: python
- from pyramid.paster import get_app, setup_logging
- ini_path = '/Users/chrism/myproject/production.ini'
- setup_logging(ini_path)
- application = get_app(ini_path, 'main')
+ from pyramid.paster import get_app, setup_logging
+ ini_path = '/Users/chrism/myproject/production.ini'
+ setup_logging(ini_path)
+ application = get_app(ini_path, 'main')
The first argument to :func:`pyramid.paster.get_app` is the project
configuration file name. It's best to use the ``production.ini`` file
@@ -106,25 +106,25 @@ specific path information for commands and files.
.. code-block:: apache
- # Use only 1 Python sub-interpreter. Multiple sub-interpreters
- # play badly with C extensions. See
- # http://stackoverflow.com/a/10558360/209039
- WSGIApplicationGroup %{GLOBAL}
- WSGIPassAuthorization On
- WSGIDaemonProcess pyramid user=chrism group=staff threads=4 \
+ # Use only 1 Python sub-interpreter. Multiple sub-interpreters
+ # play badly with C extensions. See
+ # http://stackoverflow.com/a/10558360/209039
+ WSGIApplicationGroup %{GLOBAL}
+ WSGIPassAuthorization On
+ WSGIDaemonProcess pyramid user=chrism group=staff threads=4 \
python-path=/Users/chrism/myproject/env/lib/python3.5/site-packages
- WSGIScriptAlias /myapp /Users/chrism/myproject/pyramid.wsgi
+ WSGIScriptAlias /myapp /Users/chrism/myproject/pyramid.wsgi
- <Directory /Users/chrism/myproject>
+ <Directory /Users/chrism/myproject>
WSGIProcessGroup pyramid
Require all granted
- </Directory>
+ </Directory>
#. Restart Apache
.. code-block:: bash
- $ sudo /usr/sbin/apachectl restart
+ sudo /usr/sbin/apachectl restart
#. Visit ``http://localhost/myapp`` in a browser. You should see the
sample application rendered in your browser.
diff --git a/docs/tutorials/wiki/background.rst b/docs/tutorials/wiki/background.rst
index c583b375c..c10ab9e55 100644
--- a/docs/tutorials/wiki/background.rst
+++ b/docs/tutorials/wiki/background.rst
@@ -11,8 +11,8 @@ familiar to someone with :term:`Zope` experience. It uses
URLs to code. It can also be followed by people without any prior
Python web framework experience.
-To code along with this tutorial, the developer will need a UNIX
-machine with development tools (Mac OS X with XCode, any Linux or BSD
+To code along with this tutorial, the developer will need a Unix
+machine with development tools (macOS with XCode, any Linux or BSD
variant, and so on) *or* a Windows system of any kind.
.. warning::
diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst
index 419fede62..e973cfdfe 100644
--- a/docs/tutorials/wiki/definingmodels.rst
+++ b/docs/tutorials/wiki/definingmodels.rst
@@ -43,8 +43,8 @@ Edit ``models.py``
Open ``tutorial/models.py`` file and edit it to look like the following:
.. literalinclude:: src/models/tutorial/models.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
The first thing we want to do is remove the ``MyModel`` class from the
generated ``models.py`` file. The ``MyModel`` class is only a sample and
@@ -91,6 +91,6 @@ up with a Python traceback on your console that ends with this exception:
.. code-block:: text
- ImportError: cannot import name MyModel
+ ImportError: cannot import name MyModel
This will also happen if you attempt to run the tests.
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index f4ca9b8d7..e4183b8f2 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -46,9 +46,9 @@ parameter in the ``setup()`` function.
Open ``setup.py`` and edit it to look like the following:
.. literalinclude:: src/views/setup.py
- :linenos:
- :emphasize-lines: 22
- :language: python
+ :linenos:
+ :emphasize-lines: 22
+ :language: python
Only the highlighted line needs to be added.
@@ -64,26 +64,26 @@ the newly added dependency distribution.
Make sure your current working directory is the root of the project (the
directory in which ``setup.py`` lives) and execute the following command.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ cd tutorial
- $ $VENV/bin/pip install -e .
+ cd tutorial
+ $VENV/bin/pip install -e .
On Windows:
.. code-block:: doscon
- c:\> cd tutorial
- c:\tutorial> %VENV%\Scripts\pip install -e .
+ cd tutorial
+ %VENV%\Scripts\pip install -e .
Success executing this command will end with a line to the console something
like:
.. code-block:: text
- Successfully installed docutils-0.13.1 tutorial
+ Successfully installed docutils-0.13.1 tutorial
Adding view functions in ``views.py``
@@ -93,8 +93,8 @@ It's time for a major change. Open ``tutorial/views.py`` and edit it to look
like the following:
.. literalinclude:: src/views/tutorial/views.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
We added some imports and created a regular expression to find "WikiWords".
@@ -126,9 +126,9 @@ The ``view_wiki`` view function
Following is the code for the ``view_wiki`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
- :lines: 12-14
- :lineno-match:
- :language: python
+ :lines: 12-14
+ :lineno-match:
+ :language: python
.. note:: In our code, we use an *import* that is *relative* to our package
named ``tutorial``, meaning we can omit the name of the package in the
@@ -164,9 +164,9 @@ The ``view_page`` view function
Here is the code for the ``view_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
- :lines: 16-33
- :lineno-match:
- :language: python
+ :lines: 16-33
+ :lineno-match:
+ :language: python
The ``view_page`` function is configured to respond as the default view
of a Page resource. We provide it with a ``@view_config`` decorator which
@@ -217,9 +217,9 @@ The ``add_page`` view function
Here is the code for the ``add_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
- :lines: 35-50
- :lineno-match:
- :language: python
+ :lines: 35-50
+ :lineno-match:
+ :language: python
The ``add_page`` function is configured to respond when the context resource
is a Wiki and the :term:`view name` is ``add_page``. We provide it with a
@@ -271,9 +271,9 @@ The ``edit_page`` view function
Here is the code for the ``edit_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
- :lines: 52-60
- :lineno-match:
- :language: python
+ :lines: 52-60
+ :lineno-match:
+ :language: python
The ``edit_page`` function is configured to respond when the context is
a Page resource and the :term:`view name` is ``edit_page``. We provide it
@@ -316,9 +316,9 @@ The ``view.pt`` template
Rename ``tutorial/templates/mytemplate.pt`` to ``tutorial/templates/view.pt`` and edit the emphasized lines to look like the following:
.. literalinclude:: src/views/tutorial/templates/view.pt
- :linenos:
- :language: html
- :emphasize-lines: 11-12,37-52
+ :linenos:
+ :language: html
+ :emphasize-lines: 11-12,37-52
This template is used by ``view_page()`` for displaying a single
wiki page. It includes:
@@ -335,8 +335,8 @@ The ``edit.pt`` template
Copy ``tutorial/templates/view.pt`` to ``tutorial/templates/edit.pt`` and edit the emphasized lines to look like the following:
.. literalinclude:: src/views/tutorial/templates/edit.pt
- :linenos:
- :language: html
+ :linenos:
+ :language: html
This template is used by ``add_page()`` and ``edit_page()`` for adding and
editing a wiki page. It displays a page containing a form that includes:
diff --git a/docs/tutorials/wiki/distributing.rst b/docs/tutorials/wiki/distributing.rst
index 011a94f51..36d00adb4 100644
--- a/docs/tutorials/wiki/distributing.rst
+++ b/docs/tutorials/wiki/distributing.rst
@@ -9,27 +9,27 @@ using the ``setup.py sdist`` command. The following commands assume your
current working directory contains the ``tutorial`` package and the
``setup.py`` file.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/python setup.py sdist
+ $VENV/bin/python setup.py sdist
On Windows:
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\python setup.py sdist
+ %VENV%\Scripts\python setup.py sdist
The output of such a command will be something like:
.. code-block:: text
- running sdist
- # more output
- creating dist
- Creating tar archive
- removing 'tutorial-0.0' (and everything under it)
+ running sdist
+ # more output
+ creating dist
+ Creating tar archive
+ removing 'tutorial-0.0' (and everything under it)
Note that this command creates a tarball in the "dist" subdirectory named
``tutorial-0.0.tar.gz``. You can send this file to your friends to show them
diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst
index f87d58b90..71fd0a957 100644
--- a/docs/tutorials/wiki/installation.rst
+++ b/docs/tutorials/wiki/installation.rst
@@ -23,23 +23,23 @@ We will use a :term:`cookiecutter` to create a Python package project from a Pyt
Generate a Pyramid project from a cookiecutter
----------------------------------------------
-We will create a Pyramid project in your home directory for UNIX or at the root for Windows. It is assumed you know the path to where you installed ``cookiecutter``. Issue the following commands and override the defaults in the prompts as follows.
+We will create a Pyramid project in your home directory for Unix or at the root for Windows. It is assumed you know the path to where you installed ``cookiecutter``. Issue the following commands and override the defaults in the prompts as follows.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ cd ~
- $ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master
+ cd ~
+ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> cd \
- c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master
+ cd \
+ cookiecutter gh:Pylons/pyramid-cookiecutter-zodb --checkout master
On all operating systems
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -55,19 +55,19 @@ If prompted for the first item, accept the default ``yes`` by hitting return.
Change directory into your newly created project
------------------------------------------------
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ cd tutorial
+ cd tutorial
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> cd tutorial
+ cd tutorial
Set and use a ``VENV`` environment variable
@@ -75,30 +75,30 @@ Set and use a ``VENV`` environment variable
We will set the ``VENV`` environment variable to the absolute path of the virtual environment, and use it going forward.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ export VENV=~/tutorial
+ export VENV=~/tutorial
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> set VENV=c:\tutorial
+ set VENV=c:\tutorial
Create a virtual environment
----------------------------
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ python3 -m venv $VENV
+ python3 -m venv $VENV
On Windows
^^^^^^^^^^
@@ -109,31 +109,31 @@ Python 2.7:
.. code-block:: doscon
- c:\tutorial> c:\Python27\Scripts\virtualenv %VENV%
+ c:\Python27\Scripts\virtualenv %VENV%
Python 3.6:
.. code-block:: doscon
- c:\tutorial> python -m venv %VENV%
+ python -m venv %VENV%
Upgrade packaging tools in the virtual environment
--------------------------------------------------
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pip install --upgrade pip setuptools
+ $VENV/bin/pip install --upgrade pip setuptools
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pip install --upgrade pip setuptools
+ %VENV%\Scripts\pip install --upgrade pip setuptools
.. _installing_project_in_dev_mode_zodb:
@@ -143,19 +143,19 @@ Installing the project in development mode
In order to do development on the project easily, you must "register" the project as a development egg in your workspace. We will install testing requirements at the same time. We do so with the following command.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pip install -e ".[testing]"
+ $VENV/bin/pip install -e ".[testing]"
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pip install -e ".[testing]"
+ %VENV%\Scripts\pip install -e ".[testing]"
On all operating systems
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,26 +198,26 @@ requirements, you may run the tests for the project. The following commands
provide options to py.test that specify the module for which its tests shall be
run, and to run py.test in quiet mode.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/py.test -q
+ $VENV/bin/py.test -q
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test -q
+ %VENV%\Scripts\py.test -q
For a successful test run, you should see output that ends like this:
.. code-block:: bash
- .
- 1 passed in 0.24 seconds
+ .
+ 1 passed in 0.24 seconds
Expose test coverage information
@@ -231,19 +231,19 @@ tests.
We've already installed the ``pytest-cov`` package into our virtual
environment, so we can run the tests with coverage.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/py.test --cov --cov-report=term-missing
+ $VENV/bin/py.test --cov --cov-report=term-missing
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test --cov --cov-report=term-missing
+ %VENV%\Scripts\py.test --cov --cov-report=term-missing
If successful, you will see output something like this:
@@ -280,19 +280,19 @@ These configuration files are ``pytest.ini`` and ``.coveragerc``, located at
the root of your package. Without these defaults, we would need to specify the
path to the module on which we want to run tests and coverage.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/py.test --cov=tutorial tutorial/tests.py -q
+ $VENV/bin/py.test --cov=tutorial tutorial/tests.py -q
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test --cov=tutorial tutorial\tests.py -q
+ %VENV%\Scripts\py.test --cov=tutorial tutorial\tests.py -q
py.test follows :ref:`conventions for Python test discovery
<pytest:test discovery>`, and the configuration defaults from the cookiecutter
@@ -311,19 +311,19 @@ Start the application
Start the application. See :ref:`what_is_this_pserve_thing` for more
information on ``pserve``.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pserve development.ini --reload
+ %VENV%\Scripts\pserve development.ini --reload
.. note::
diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst
index cd82c0118..c3a1ca79a 100644
--- a/docs/tutorials/wiki/tests.rst
+++ b/docs/tutorials/wiki/tests.rst
@@ -45,8 +45,8 @@ Open the ``tutorial/tests.py`` module, and edit it such that it appears as
follows:
.. literalinclude:: src/tests/tutorial/tests.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
Running the tests
=================
@@ -56,17 +56,17 @@ We can run these tests by using ``py.test`` similarly to how we did in
already been satisfied and ``py.test`` and coverage have already been
configured, so we can jump right to running tests.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/py.test -q
+ $VENV/bin/py.test -q
On Windows:
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test -q
+ %VENV%\Scripts\py.test -q
The expected result should look like the following:
diff --git a/docs/tutorials/wiki2/background.rst b/docs/tutorials/wiki2/background.rst
index ee7dfe36f..c14d3cb7d 100644
--- a/docs/tutorials/wiki2/background.rst
+++ b/docs/tutorials/wiki2/background.rst
@@ -11,8 +11,8 @@ familiar to someone with SQL database experience. It uses
URLs to code. It can also be followed by people without any prior
Python web framework experience.
-To code along with this tutorial, the developer will need a UNIX
-machine with development tools (Mac OS X with XCode, any Linux or BSD
+To code along with this tutorial, the developer will need a Unix
+machine with development tools (macOS with XCode, any Linux or BSD
variant, etc.) *or* a Windows system of any kind.
.. note::
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 233231f8d..313b5998e 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -21,24 +21,24 @@ code.
Open ``tutorial/__init__.py``. It should already contain the following:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
Let's go over this piece-by-piece. First we need some imports to support later
code:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :end-before: main
- :lineno-match:
- :language: py
+ :end-before: main
+ :lineno-match:
+ :language: py
``__init__.py`` defines a function named ``main``. Here is the entirety of
the ``main`` function we've defined in our ``__init__.py``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :pyobject: main
- :lineno-match:
- :language: py
+ :pyobject: main
+ :lineno-match:
+ :language: py
When you invoke the ``pserve development.ini`` command, the ``main`` function
above is executed. It accepts some settings and returns a :term:`WSGI`
@@ -47,9 +47,9 @@ application. (See :ref:`startup_chapter` for more about ``pserve``.)
Next in ``main``, construct a :term:`Configurator` object:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 7
- :lineno-match:
- :language: py
+ :lines: 7
+ :lineno-match:
+ :language: py
``settings`` is passed to the ``Configurator`` as a keyword argument with the
dictionary values passed as the ``**settings`` argument. This will be a
@@ -61,25 +61,25 @@ Next include :term:`Jinja2` templating bindings so that we can use renderers
with the ``.jinja2`` extension within our project.
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 8
- :lineno-match:
- :language: py
+ :lines: 8
+ :lineno-match:
+ :language: py
Next include the the package ``models`` using a dotted Python path. The exact
setup of the models will be covered later.
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 9
- :lineno-match:
- :language: py
+ :lines: 9
+ :lineno-match:
+ :language: py
Next include the ``routes`` module using a dotted Python path. This module will
be explained in the next section.
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 10
- :lineno-match:
- :language: py
+ :lines: 10
+ :lineno-match:
+ :language: py
.. note::
@@ -95,18 +95,18 @@ will be registered, allowing one of our application URLs to be mapped to some
code.
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 11
- :lineno-match:
- :language: py
+ :lines: 11
+ :lineno-match:
+ :language: py
Finally ``main`` is finished configuring things, so it uses the
:meth:`pyramid.config.Configurator.make_wsgi_app` method to return a
:term:`WSGI` application:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 12
- :lineno-match:
- :language: py
+ :lines: 12
+ :lineno-match:
+ :language: py
Route declarations
@@ -115,8 +115,8 @@ Route declarations
Open the ``tutorial/routes.py`` file. It should already contain the following:
.. literalinclude:: src/basiclayout/tutorial/routes.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
On line 2, we call :meth:`pyramid.config.Configurator.add_static_view` with
three arguments: ``static`` (the name), ``static`` (the path), and
@@ -151,8 +151,8 @@ Open ``tutorial/views/default.py`` in the ``views`` package. It should already
contain the following:
.. literalinclude:: src/basiclayout/tutorial/views/default.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
The important part here is that the ``@view_config`` decorator associates the
function it decorates (``my_view``) with a :term:`view configuration`,
@@ -195,17 +195,17 @@ First, open ``tutorial/models/meta.py``, which should already contain the
following:
.. literalinclude:: src/basiclayout/tutorial/models/meta.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
``meta.py`` contains imports and support code for defining the models. We
create a dictionary ``NAMING_CONVENTION`` as well for consistent naming of
support objects like indices and constraints.
.. literalinclude:: src/basiclayout/tutorial/models/meta.py
- :end-before: metadata
- :linenos:
- :language: py
+ :end-before: metadata
+ :linenos:
+ :language: py
Next we create a ``metadata`` object from the class
:class:`sqlalchemy.schema.MetaData`, using ``NAMING_CONVENTION`` as the value
@@ -218,25 +218,25 @@ will attach the tables to the ``metadata`` we created, and define our
application's database schema.
.. literalinclude:: src/basiclayout/tutorial/models/meta.py
- :lines: 15-16
- :lineno-match:
- :language: py
+ :lines: 15-16
+ :lineno-match:
+ :language: py
Next open ``tutorial/models/mymodel.py``, which should already contain the
following:
.. literalinclude:: src/basiclayout/tutorial/models/mymodel.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
Notice we've defined the ``models`` as a package to make it straightforward for
defining models in separate modules. To give a simple example of a model class,
we have defined one named ``MyModel`` in ``mymodel.py``:
.. literalinclude:: src/basiclayout/tutorial/models/mymodel.py
- :pyobject: MyModel
- :lineno-match:
- :language: py
+ :pyobject: MyModel
+ :lineno-match:
+ :language: py
Our example model does not require an ``__init__`` method because SQLAlchemy
supplies for us a default constructor, if one is not already present, which
@@ -244,9 +244,9 @@ accepts keyword arguments of the same name as that of the mapped attributes.
.. note:: Example usage of MyModel:
- .. code-block:: python
+ .. code-block:: python
- johnny = MyModel(name="John Doe", value=10)
+ johnny = MyModel(name="John Doe", value=10)
The ``MyModel`` class has a ``__tablename__`` attribute. This informs
SQLAlchemy which table to use to store the data representing instances of this
@@ -256,8 +256,8 @@ Finally, open ``tutorial/models/__init__.py``, which should already
contain the following:
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
Our ``models/__init__.py`` module defines the primary API we will use for
configuring the database connections within our application, and it contains
@@ -286,9 +286,9 @@ database engine using :func:`sqlalchemy.engine_from_config` from the
``[app:main]`` section. This setting is a URI (something like ``sqlite://``).
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
- :pyobject: get_engine
- :lineno-match:
- :language: py
+ :pyobject: get_engine
+ :lineno-match:
+ :language: py
The function ``get_session_factory`` accepts an :term:`SQLAlchemy` database
engine, and creates a ``session_factory`` from the :term:`SQLAlchemy` class
@@ -296,9 +296,9 @@ engine, and creates a ``session_factory`` from the :term:`SQLAlchemy` class
used for creating sessions bound to the database engine.
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
- :pyobject: get_session_factory
- :lineno-match:
- :language: py
+ :pyobject: get_session_factory
+ :lineno-match:
+ :language: py
The function ``get_tm_session`` registers a database session with a transaction
manager, and returns a ``dbsession`` object. With the transaction manager, our
@@ -306,9 +306,9 @@ application will automatically issue a transaction commit after every request,
unless an exception is raised, in which case the transaction will be aborted.
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
- :pyobject: get_tm_session
- :lineno-match:
- :language: py
+ :pyobject: get_tm_session
+ :lineno-match:
+ :language: py
Finally, we define an ``includeme`` function, which is a hook for use with
:meth:`pyramid.config.Configurator.include` to activate code in a Pyramid
@@ -319,9 +319,9 @@ define a ``request.dbsession`` property, which we can use to do work on behalf
of an incoming request to our application.
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
- :pyobject: includeme
- :lineno-match:
- :language: py
+ :pyobject: includeme
+ :lineno-match:
+ :language: py
That's about all there is to it regarding models, views, and initialization
code in our stock application.
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index c22fd2b61..9159027c4 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -32,9 +32,9 @@ parameter in the ``setup()`` function.
Open ``tutorial/setup.py`` and edit it to look like the following:
.. literalinclude:: src/models/setup.py
- :linenos:
- :emphasize-lines: 13
- :language: python
+ :linenos:
+ :emphasize-lines: 13
+ :language: python
Only the highlighted line needs to be added.
@@ -53,17 +53,17 @@ the newly added dependency distribution.
Make sure your current working directory is the root of the project (the
directory in which ``setup.py`` lives) and execute the following command.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
On Windows:
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pip install -e .
+ %VENV%\Scripts\pip install -e .
Success executing this command will end with a line to the console something
like the following.
@@ -86,8 +86,8 @@ Add ``user.py``
Create a new file ``tutorial/models/user.py`` with the following contents:
.. literalinclude:: src/models/tutorial/models/user.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
This is a very basic model for a user who can authenticate with our wiki.
@@ -125,8 +125,8 @@ Add ``page.py``
Create a new file ``tutorial/models/page.py`` with the following contents:
.. literalinclude:: src/models/tutorial/models/page.py
- :linenos:
- :language: py
+ :linenos:
+ :language: py
As you can see, our ``Page`` class is very similar to the ``User`` defined
above, except with attributes focused on storing information about a wiki page,
@@ -151,9 +151,9 @@ Open the ``tutorial/models/__init__.py`` file and edit it to look like
the following:
.. literalinclude:: src/models/tutorial/models/__init__.py
- :linenos:
- :language: py
- :emphasize-lines: 8,9
+ :linenos:
+ :language: py
+ :emphasize-lines: 8,9
Here we align our imports with the names of the models, ``Page`` and ``User``.
@@ -165,21 +165,21 @@ Migrate the database with Alembic
Now that we have written our models, we need to modify the database schema to reflect the changes to our code. Let's generate a new revision, then upgrade the database to the latest revision (head).
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/alembic -c development.ini revision --autogenerate \
- -m "use new models Page and User"
- $ $VENV/bin/alembic -c development.ini upgrade head
+ $VENV/bin/alembic -c development.ini revision --autogenerate \
+ -m "use new models Page and User"
+ $VENV/bin/alembic -c development.ini upgrade head
On Windows:
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\alembic -c development.ini revision \
- --autogenerate -m "use new models Page and User"
- c:\tutorial> %VENV%\Scripts\alembic -c development.ini upgrade head
+ %VENV%\Scripts\alembic -c development.ini revision \
+ --autogenerate -m "use new models Page and User"
+ %VENV%\Scripts\alembic -c development.ini upgrade head
Success executing these commands will generate output similar to the following.
@@ -308,9 +308,9 @@ Open ``tutorial/scripts/initialize_db.py`` and edit it to look like the
following:
.. literalinclude:: src/models/tutorial/scripts/initialize_db.py
- :linenos:
- :language: python
- :emphasize-lines: 11-24
+ :linenos:
+ :language: python
+ :emphasize-lines: 11-24
Only the highlighted lines need to be changed.
@@ -351,6 +351,6 @@ your console that ends with this exception:
.. code-block:: text
- AttributeError: module 'tutorial.models' has no attribute 'MyModel'
+ AttributeError: module 'tutorial.models' has no attribute 'MyModel'
This will also happen if you attempt to run the tests.
diff --git a/docs/tutorials/wiki2/distributing.rst b/docs/tutorials/wiki2/distributing.rst
index d296363ed..0eff63461 100644
--- a/docs/tutorials/wiki2/distributing.rst
+++ b/docs/tutorials/wiki2/distributing.rst
@@ -9,27 +9,27 @@ using the ``setup.py sdist`` command. The following commands assume your
current working directory contains the ``tutorial`` package and the
``setup.py`` file.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ $VENV/bin/python setup.py sdist
+ $VENV/bin/python setup.py sdist
On Windows:
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\python setup.py sdist
+ %VENV%\Scripts\python setup.py sdist
The output of such a command will be something like:
.. code-block:: text
- running sdist
- # more output
- creating dist
- Creating tar archive
- removing 'tutorial-0.0' (and everything under it)
+ running sdist
+ # more output
+ creating dist
+ Creating tar archive
+ removing 'tutorial-0.0' (and everything under it)
Note that this command creates a tarball in the ``dist`` subdirectory named
``tutorial-0.0.tar.gz``. You can send this file to your friends to show them
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index 9b89327cb..1fa7e21d7 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -24,7 +24,7 @@ If you need to install the SQLite3 packages, then, for example, using the Debian
.. code-block:: bash
- $ sudo apt-get install libsqlite3-dev
+ sudo apt-get install libsqlite3-dev
Install cookiecutter
@@ -35,23 +35,23 @@ We will use a :term:`cookiecutter` to create a Python package project from a Pyt
Generate a Pyramid project from a cookiecutter
----------------------------------------------
-We will create a Pyramid project in your home directory for UNIX or at the root for Windows. It is assumed you know the path to where you installed ``cookiecutter``. Issue the following commands and override the defaults in the prompts as follows.
+We will create a Pyramid project in your home directory for Unix or at the root for Windows. It is assumed you know the path to where you installed ``cookiecutter``. Issue the following commands and override the defaults in the prompts as follows.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ cd ~
- $ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master
+ cd ~
+ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> cd \
- c:\> cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master
+ cd \
+ cookiecutter gh:Pylons/pyramid-cookiecutter-alchemy --checkout master
On all operating systems
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -67,19 +67,19 @@ If prompted for the first item, accept the default ``yes`` by hitting return.
Change directory into your newly created project
------------------------------------------------
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ cd tutorial
+ cd tutorial
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> cd tutorial
+ cd tutorial
Set and use a ``VENV`` environment variable
@@ -87,30 +87,30 @@ Set and use a ``VENV`` environment variable
We will set the ``VENV`` environment variable to the absolute path of the virtual environment, and use it going forward.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ export VENV=~/tutorial
+ export VENV=~/tutorial
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> set VENV=c:\tutorial
+ set VENV=c:\tutorial
Create a virtual environment
----------------------------
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ python3 -m venv $VENV
+ python3 -m venv $VENV
On Windows
^^^^^^^^^^
@@ -121,31 +121,31 @@ Python 2.7:
.. code-block:: doscon
- c:\tutorial> c:\Python27\Scripts\virtualenv %VENV%
+ c:\Python27\Scripts\virtualenv %VENV%
Python 3.6:
.. code-block:: doscon
- c:\tutorial> python -m venv %VENV%
+ python -m venv %VENV%
Upgrade packaging tools in the virtual environment
--------------------------------------------------
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pip install --upgrade pip setuptools
+ $VENV/bin/pip install --upgrade pip setuptools
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pip install --upgrade pip setuptools
+ %VENV%\Scripts\pip install --upgrade pip setuptools
.. _installing_project_in_dev_mode:
@@ -155,19 +155,19 @@ Installing the project in development mode
In order to do development on the project easily, you must "register" the project as a development egg in your workspace. We will install testing requirements at the same time. We do so with the following command.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pip install -e ".[testing]"
+ $VENV/bin/pip install -e ".[testing]"
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pip install -e ".[testing]"
+ %VENV%\Scripts\pip install -e ".[testing]"
On all operating systems
^^^^^^^^^^^^^^^^^^^^^^^^
@@ -188,14 +188,14 @@ The console will show ``pip`` checking for packages and installing missing packa
Testing requirements are defined in our project's ``setup.py`` file, in the ``tests_require`` and ``extras_require`` stanzas.
.. literalinclude:: src/installation/setup.py
- :language: python
- :lineno-match:
- :lines: 24-28
+ :language: python
+ :lineno-match:
+ :lines: 24-28
.. literalinclude:: src/installation/setup.py
- :language: python
- :lineno-match:
- :lines: 48-50
+ :language: python
+ :lineno-match:
+ :lines: 48-50
.. _initialize_db_wiki2:
@@ -207,93 +207,93 @@ We use :term:`Alembic` to manage our database initialization and migrations.
Generate your first revision.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/alembic -c development.ini revision --autogenerate -m "init"
+ $VENV/bin/alembic -c development.ini revision --autogenerate -m "init"
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\alembic -c development.ini revision --autogenerate -m "init"
+ %VENV%\Scripts\alembic -c development.ini revision --autogenerate -m "init"
The output to your console should be something like this:
.. code-block:: text
- 2018-06-22 17:57:31,587 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
- 2018-06-22 17:57:31,587 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
- 2018-06-22 17:57:31,588 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
- 2018-06-22 17:57:31,588 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
- 2018-06-22 17:57:31,589 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
- 2018-06-22 17:57:31,589 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:31,590 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
- 2018-06-22 17:57:31,590 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:31,590 INFO [sqlalchemy.engine.base.Engine:1151][MainThread]
- CREATE TABLE alembic_version (
+ 2018-06-22 17:57:31,587 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
+ 2018-06-22 17:57:31,587 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
+ 2018-06-22 17:57:31,588 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
+ 2018-06-22 17:57:31,588 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
+ 2018-06-22 17:57:31,589 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
+ 2018-06-22 17:57:31,589 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:31,590 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
+ 2018-06-22 17:57:31,590 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:31,590 INFO [sqlalchemy.engine.base.Engine:1151][MainThread]
+ CREATE TABLE alembic_version (
version_num VARCHAR(32) NOT NULL,
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
- )
+ )
- 2018-06-22 17:57:31,591 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:31,591 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
- 2018-06-22 17:57:31,594 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
- 2018-06-22 17:57:31,594 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:31,591 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:31,591 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
+ 2018-06-22 17:57:31,594 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
+ 2018-06-22 17:57:31,594 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
Generating /<somepath>/tutorial/alembic/versions/20180622_bab5a278ce04.py ... done
Upgrade to that revision.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/alembic -c development.ini upgrade head
+ $VENV/bin/alembic -c development.ini upgrade head
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\alembic -c development.ini upgrade head
+ %VENV%\Scripts\alembic -c development.ini upgrade head
The output to your console should be something like this:
.. code-block:: text
- 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
- 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
- 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
- 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
- 2018-06-22 17:57:37,816 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
- 2018-06-22 17:57:37,816 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] SELECT alembic_version.version_num
- FROM alembic_version
- 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
- 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:37,819 INFO [sqlalchemy.engine.base.Engine:1151][MainThread]
- CREATE TABLE models (
+ 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
+ 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
+ 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
+ 2018-06-22 17:57:37,814 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
+ 2018-06-22 17:57:37,816 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
+ 2018-06-22 17:57:37,816 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] SELECT alembic_version.version_num
+ FROM alembic_version
+ 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] PRAGMA table_info("alembic_version")
+ 2018-06-22 17:57:37,817 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:37,819 INFO [sqlalchemy.engine.base.Engine:1151][MainThread]
+ CREATE TABLE models (
id INTEGER NOT NULL,
name TEXT,
value INTEGER,
CONSTRAINT pk_models PRIMARY KEY (id)
- )
+ )
- 2018-06-22 17:57:37,820 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:37,822 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
- 2018-06-22 17:57:37,824 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] CREATE UNIQUE INDEX my_index ON models (name)
- 2018-06-22 17:57:37,824 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
- 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] INSERT INTO alembic_version (version_num) VALUES ('bab5a278ce04')
- 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
- 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
+ 2018-06-22 17:57:37,820 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:37,822 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
+ 2018-06-22 17:57:37,824 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] CREATE UNIQUE INDEX my_index ON models (name)
+ 2018-06-22 17:57:37,824 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
+ 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] INSERT INTO alembic_version (version_num) VALUES ('bab5a278ce04')
+ 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ()
+ 2018-06-22 17:57:37,825 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
.. _load_data_wiki2:
@@ -303,32 +303,32 @@ Load default data
Load default data into the database using a :term:`console script`. Type the following command, making sure you are still in the ``tutorial`` directory (the directory with a ``development.ini`` in it):
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/initialize_tutorial_db development.ini
+ $VENV/bin/initialize_tutorial_db development.ini
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\initialize_tutorial_db development.ini
+ %VENV%\Scripts\initialize_tutorial_db development.ini
The output to your console should be something like this:
.. code-block:: bash
- 2018-06-22 17:57:46,241 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
- 2018-06-22 17:57:46,241 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
- 2018-06-22 17:57:46,242 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
- 2018-06-22 17:57:46,242 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
- 2018-06-22 17:57:46,243 INFO [sqlalchemy.engine.base.Engine:682][MainThread] BEGIN (implicit)
- 2018-06-22 17:57:46,244 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] INSERT INTO models (name, value) VALUES (?, ?)
- 2018-06-22 17:57:46,245 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ('one', 1)
- 2018-06-22 17:57:46,246 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
+ 2018-06-22 17:57:46,241 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
+ 2018-06-22 17:57:46,241 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
+ 2018-06-22 17:57:46,242 INFO [sqlalchemy.engine.base.Engine:1254][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
+ 2018-06-22 17:57:46,242 INFO [sqlalchemy.engine.base.Engine:1255][MainThread] ()
+ 2018-06-22 17:57:46,243 INFO [sqlalchemy.engine.base.Engine:682][MainThread] BEGIN (implicit)
+ 2018-06-22 17:57:46,244 INFO [sqlalchemy.engine.base.Engine:1151][MainThread] INSERT INTO models (name, value) VALUES (?, ?)
+ 2018-06-22 17:57:46,245 INFO [sqlalchemy.engine.base.Engine:1154][MainThread] ('one', 1)
+ 2018-06-22 17:57:46,246 INFO [sqlalchemy.engine.base.Engine:722][MainThread] COMMIT
Success! You should now have a ``tutorial.sqlite`` file in your current
working directory. This is an SQLite database with a single table defined in it
@@ -345,26 +345,26 @@ requirements, you may run the tests for the project. The following commands
provide options to py.test that specify the module for which its tests shall be
run, and to run py.test in quiet mode.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/py.test -q
+ $VENV/bin/py.test -q
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test -q
+ %VENV%\Scripts\py.test -q
For a successful test run, you should see output that ends like this:
.. code-block:: bash
- ..
- 2 passed in 0.44 seconds
+ ..
+ 2 passed in 0.44 seconds
Expose test coverage information
@@ -378,19 +378,19 @@ tests.
We've already installed the ``pytest-cov`` package into our virtual
environment, so we can run the tests with coverage.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/py.test --cov --cov-report=term-missing
+ $VENV/bin/py.test --cov --cov-report=term-missing
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test --cov --cov-report=term-missing
+ c:\tutorial> %VENV%\Scripts\py.test --cov --cov-report=term-missing
If successful, you will see output something like this:
@@ -404,20 +404,20 @@ If successful, you will see output something like this:
tutorial/tests.py ..
------------------ coverage: platform Python 3.6.5 ------------------
- Name Stmts Miss Cover Missing
- -----------------------------------------------------------------
- tutorial/__init__.py 8 6 25% 7-12
- tutorial/models/__init__.py 24 0 100%
- tutorial/models/meta.py 5 0 100%
- tutorial/models/mymodel.py 8 0 100%
- tutorial/routes.py 3 3 0% 1-3
- tutorial/scripts/__init__.py 0 0 100%
- tutorial/scripts/initialize_db.py 24 24 0% 1-34
- tutorial/views/__init__.py 0 0 100%
- tutorial/views/default.py 12 0 100%
- tutorial/views/notfound.py 4 4 0% 1-7
- -----------------------------------------------------------------
- TOTAL 88 37 58%
+ Name Stmts Miss Cover Missing
+ -----------------------------------------------------------------
+ tutorial/__init__.py 8 6 25% 7-12
+ tutorial/models/__init__.py 24 0 100%
+ tutorial/models/meta.py 5 0 100%
+ tutorial/models/mymodel.py 8 0 100%
+ tutorial/routes.py 3 3 0% 1-3
+ tutorial/scripts/__init__.py 0 0 100%
+ tutorial/scripts/initialize_db.py 24 24 0% 1-34
+ tutorial/views/__init__.py 0 0 100%
+ tutorial/views/default.py 12 0 100%
+ tutorial/views/notfound.py 4 4 0% 1-7
+ -----------------------------------------------------------------
+ TOTAL 88 37 58%
===================== 2 passed in 0.57 seconds ======================
@@ -434,19 +434,19 @@ These configuration files are ``pytest.ini`` and ``.coveragerc``, located at
the root of your package. Without these defaults, we would need to specify the
path to the module on which we want to run tests and coverage.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/py.test --cov=tutorial tutorial/tests.py -q
+ $VENV/bin/py.test --cov=tutorial tutorial/tests.py -q
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\py.test --cov=tutorial tutorial\tests.py -q
+ %VENV%\Scripts\py.test --cov=tutorial tutorial\tests.py -q
py.test follows :ref:`conventions for Python test discovery
<pytest:test discovery>`, and the configuration defaults from the cookiecutter
@@ -465,19 +465,19 @@ Start the application
Start the application. See :ref:`what_is_this_pserve_thing` for more
information on ``pserve``.
-On UNIX
+On Unix
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pserve development.ini --reload
+ $VENV/bin/pserve development.ini --reload
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\tutorial> %VENV%\Scripts\pserve development.ini --reload
+ %VENV%\Scripts\pserve development.ini --reload
.. note::
diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst
index 84b123df1..f3f89fe9c 100644
--- a/docs/tutorials/wiki2/tests.rst
+++ b/docs/tutorials/wiki2/tests.rst
@@ -53,33 +53,32 @@ View the results of all our edits to ``tests`` subpackage
Create ``tutorial/tests/test_views.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_views.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
Create ``tutorial/tests/test_functional.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_functional.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
Create ``tutorial/tests/test_initdb.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_initdb.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
Create ``tutorial/tests/test_security.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_security.py
- :linenos:
- :language: python
+ :linenos:
+ :language: python
Create ``tutorial/tests/test_user_model.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_user_model.py
- :linenos:
- :language: python
-
+ :linenos:
+ :language: python
.. note::
@@ -95,25 +94,25 @@ Running the tests
We can run these tests similarly to how we did in :ref:`running_tests`, but first delete the SQLite database ``tutorial.sqlite``. If you do not delete the database, then you will see an integrity error when running the tests.
-On UNIX:
+On Unix:
.. code-block:: bash
- $ rm tutorial.sqlite
- $ $VENV/bin/py.test -q
+ rm tutorial.sqlite
+ $VENV/bin/py.test -q
On Windows:
.. code-block:: doscon
- c:\tutorial> del tutorial.sqlite
- c:\tutorial> %VENV%\Scripts\py.test -q
+ del tutorial.sqlite
+ %VENV%\Scripts\py.test -q
The expected result should look like the following:
.. code-block:: text
- ................................
- 32 passed in 9.90 seconds
+ ................................
+ 32 passed in 9.90 seconds
.. _webtest: https://docs.pylonsproject.org/projects/webtest/en/latest/
diff --git a/docs/typographical-conventions.rst b/docs/typographical-conventions.rst
index 2bfe4ffa6..76fdf8ace 100644
--- a/docs/typographical-conventions.rst
+++ b/docs/typographical-conventions.rst
@@ -73,17 +73,17 @@ XML:
<somesnippet>Some XML</somesnippet>
-Unix shell commands are prefixed with a ``$`` character. (See :term:`venv` for the meaning of ``$VENV``.)
+Unix shell commands (See :term:`venv` for the meaning of ``$VENV``.):
.. code-block:: bash
- $ $VENV/bin/pip install -e .
+ $VENV/bin/pip install -e .
-Windows commands are prefixed with a drive letter with an optional directory name. (See :term:`venv` for the meaning of ``%VENV%``.)
+Windows commands (See :term:`venv` for the meaning of ``%VENV%``.):
.. code-block:: doscon
- c:\> %VENV%\Scripts\pserve development.ini
+ %VENV%\Scripts\pserve development.ini
cfg:
@@ -128,7 +128,7 @@ When a command that should be typed on one line is too long to fit on the displa
.. code-block:: bash
- $ $VENV/bin/py.test tutorial/tests.py --cov-report term-missing \
+ $VENV/bin/py.test tutorial/tests.py --cov-report term-missing \
--cov=tutorial -q
diff --git a/docs/whatsnew-1.1.rst b/docs/whatsnew-1.1.rst
index a5c7f3393..2427a0074 100644
--- a/docs/whatsnew-1.1.rst
+++ b/docs/whatsnew-1.1.rst
@@ -395,7 +395,7 @@ Deprecations and Behavior Differences
when porting your application from an older version of Pyramid. Use the
``PYTHONWARNINGS`` environment variable with the value ``all`` in the
shell you use to invoke ``paster serve`` to see these warnings, e.g. on
- UNIX, ``PYTHONWARNINGS=all $VENV/bin/paster serve development.ini``.
+ Unix, ``PYTHONWARNINGS=all $VENV/bin/paster serve development.ini``.
Python 2.5 and 2.6 show deprecation warnings by default,
so this is unnecessary there.
All deprecation warnings are emitted to the console.