diff options
| author | Michael Merickel <github@m.merickel.org> | 2018-08-21 01:44:55 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-21 01:44:55 -0500 |
| commit | 820a752645b460ea8009b07a75c752ab09c53dec (patch) | |
| tree | 14616d81a7abedfe523c057e71ed7b2aca680754 /docs/narr | |
| parent | df8598a2658632f709a64e8076cce02ca49de8e6 (diff) | |
| parent | 254710cb716dccfe536b20d077e3cb79be19c6b3 (diff) | |
| download | pyramid-820a752645b460ea8009b07a75c752ab09c53dec.tar.gz pyramid-820a752645b460ea8009b07a75c752ab09c53dec.tar.bz2 pyramid-820a752645b460ea8009b07a75c752ab09c53dec.zip | |
Merge pull request #3330 from stevepiercy/docs-code-style
Docs code style
Diffstat (limited to 'docs/narr')
35 files changed, 2813 insertions, 2814 deletions
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 |
