4 files deleted
11 files added
176 files modified
| | |
| | | Features |
| | | -------- |
| | | |
| | | - New request attribute: ``json``. If the request's ``content_type`` is |
| | | ``application/json``, this attribute will contain the JSON-decoded |
| | | variant of the request body. If the request's ``content_type`` is not |
| | | ``application/json``, this attribute will be ``None``. |
| | | - Added a ``pyramid.security.NO_PERMISSION_REQUIRED`` constant for use in |
| | | ``permission=`` statements to view configuration. This constant has a |
| | | value of the string ``__no_permission_required__``. This string value was |
| | | previously referred to in documentation; now the documentation uses the |
| | | constant. |
| | | |
| | | - Added a decorator-based way to configure a response adapter: |
| | | ``pyramid.response.response_adapter``. This decorator has the same use as |
| | | ``pyramid.config.Configurator.add_response_adapter`` but it's declarative. |
| | | |
| | | - The ``pyramid.events.BeforeRender`` event now has an attribute named |
| | | ``rendering_val``. This can be used to introspect the value returned by a |
| | | view in a BeforeRender subscriber. |
| | | |
| | | - New configurator directive: ``pyramid.config.Configurator.add_tween``. |
| | | This directive adds a "tween". A "tween" is used to wrap the Pyramid |
| | | router's primary request handling function. This is a feature may be used |
| | | by Pyramid framework extensions, to provide, for example, view timing |
| | | support and as a convenient place to hang bookkeeping code. |
| | | |
| | | Tweens are further described in the narrative docs section in the Hooks |
| | | chapter, named "Registering Tweens". |
| | | |
| | | - New paster command ``paster ptweens``, which prints the current "tween" |
| | | configuration for an application. See the section entitled "Displaying |
| | | Tweens" in the Command-Line Pyramid chapter of the narrative documentation |
| | | for more info. |
| | | |
| | | - The Pyramid debug logger now uses the standard logging configuration |
| | | (usually set up by Paste as part of startup). This means that output from |
| | | e.g. ``debug_notfound``, ``debug_authorization``, etc. will go to the |
| | | normal logging channels. The logger name of the debug logger will be the |
| | | package name of the *caller* of the Configurator's constructor. |
| | | |
| | | - A new attribute is available on request objects: ``exc_info``. Its value |
| | | will be ``None`` until an exception is caught by the Pyramid router, after |
| | | which it will be the result of ``sys.exc_info()``. |
| | | |
| | | Internal |
| | | -------- |
| | | |
| | | - The Pyramid "exception view" machinery is now implemented as a "tween" |
| | | (``pyramid.tweens.excview_tween_factory``). |
| | | |
| | | Deprecations |
| | | ------------ |
| | | |
| | | - All Pyramid-related deployment settings (e.g. ``debug_all``, |
| | | ``debug_notfound``) are now meant to be prefixed with the prefix |
| | | ``pyramid.``. For example: ``debug_all`` -> ``pyramid.debug_all``. The |
| | | old non-prefixed settings will continue to work indefinitely but supplying |
| | | them may print a deprecation warning. All scaffolds and tutorials have |
| | | been changed to use prefixed settings. |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | | - If a string is passed as the ``debug_logger`` parameter to a Configurator, |
| | | that string is considered to be the name of a global Python logger rather |
| | | than a dotted name to an instance of a logger. |
| | | |
| | | Documentation |
| | | ------------- |
| | | |
| | | - Added a new module to the API docs: ``pyramid.tweens``. |
| | | |
| | | - Added a "Registering Tweens" section to the "Hooks" narrative chapter. |
| | | |
| | | - Added a "Displaying Tweens" section to the "Command-Line Pyramid" narrative |
| | | chapter. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - Fixed an issue with the default renderer not working at certain times. See |
| | | https://github.com/Pylons/pyramid/issues/249 |
| | | |
| | | 1.1 (2011-07-22) |
| | | ================ |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - Added the ``pyramid.renderers.null_renderer`` object as an API. The null |
| | | renderer is an object that can be used in advanced integration cases as |
| | | input to the view configuration ``renderer=`` argument. When the null |
| | | renderer is used as a view renderer argument, Pyramid avoids converting the |
| | | view callable result into a Response object. This is useful if you want to |
| | | reuse the view configuration and lookup machinery outside the context of |
| | | its use by the Pyramid router. This feature was added for consumption by |
| | | the ``pyramid_rpc`` package, which uses view configuration and lookup |
| | | outside the context of a router in exactly this way. ``pyramid_rpc`` has |
| | | been broken under 1.1 since 1.1b1; adding it allows us to make it work |
| | | again. |
| | | |
| | | - Change all scaffolding templates that point to docs.pylonsproject.org to |
| | | use ``/projects/pyramid/current`` rather than ``/projects/pyramid/dev``. |
| | | |
| | | Internals |
| | | --------- |
| | | |
| | | - Remove ``compat`` code that served only the purpose of providing backwards |
| | | compatibility with Python 2.4. |
| | | |
| | | - Add a deprecation warning for non-API function |
| | | ``pyramid.renderers.renderer_from_name`` which has seen use in the wild. |
| | | |
| | | - Add a ``clone`` method to ``pyramid.renderers.RendererHelper`` for use by |
| | | the ``pyramid.view.view_config`` decorator. |
| | | |
| | | Documentation |
| | | ------------- |
| | | |
| | | - Fixed two typos in wiki2 (SQLA + URL Dispatch) tutorial. |
| | | |
| | | - Reordered chapters in narrative section for better new user friendliness. |
| | | |
| | | - Added more indexing markers to sections in documentation. |
| | | |
| | | 1.1b4 (2011-07-18) |
| | | ================== |
| | | |
| | | Documentation |
| | | ------------- |
| | | |
| | | - Added a section entitled "Writing a Script" to the "Command-Line Pyramid" |
| | | chapter. |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | | - We added the ``pyramid.scripting.make_request`` API too hastily in 1.1b3. |
| | | It has been removed. Sorry for any inconvenience. Use the |
| | | ``pyramid.request.Request.blank`` API instead. |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - The ``paster pshell``, ``paster pviews``, and ``paster proutes`` commands |
| | | each now under the hood uses ``pyramid.paster.bootstrap``, which makes it |
| | | possible to supply an ``.ini`` file without naming the "right" section in |
| | | the file that points at the actual Pyramid application. Instead, you can |
| | | generally just run ``paster {pshell|proutes|pviews} development.ini`` and |
| | | it will do mostly the right thing. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - Omit custom environ variables when rendering a custom exception template in |
| | | ``pyramid.httpexceptions.WSGIHTTPException._set_default_attrs``; |
| | | stringifying thse may trigger code that should not be executed; see |
| | | https://github.com/Pylons/pyramid/issues/239 |
| | | |
| | | 1.1b3 (2011-07-15) |
| | | ================== |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - Fix corner case to ease semifunctional testing of views: create a new |
| | | rendererinfo to clear out old registry on a rescan. See |
| | | https://github.com/Pylons/pyramid/pull/234. |
| | | |
| | | - New API class: ``pyramid.static.static_view``. This supersedes the |
| | | deprecated ``pyramid.view.static`` class. ``pyramid.static.static_view`` |
| | | by default serves up documents as the result of the request's |
| | | ``path_info``, attribute rather than it's ``subpath`` attribute (the |
| | | inverse was true of ``pyramid.view.static``, and still is). |
| | | ``pyramid.static.static_view`` exposes a ``use_subpath`` flag for use when |
| | | you want the static view to behave like the older deprecated version. |
| | | |
| | | - A new API function ``pyramid.paster.bootstrap`` has been added to make |
| | | writing scripts that bootstrap a Pyramid environment easier, e.g.:: |
| | | |
| | | from pyramid.paster import bootstrap |
| | | info = bootstrap('/path/to/my/development.ini') |
| | | request = info['request'] |
| | | print request.route_url('myroute') |
| | | |
| | | - A new API function ``pyramid.scripting.prepare`` has been added. It is a |
| | | lower-level analogue of ``pyramid.paster.boostrap`` that accepts a request |
| | | and a registry instead of a config file argument, and is used for the same |
| | | purpose:: |
| | | |
| | | from pyramid.scripting import prepare |
| | | info = prepare(registry=myregistry) |
| | | request = info['request'] |
| | | print request.route_url('myroute') |
| | | |
| | | - A new API function ``pyramid.scripting.make_request`` has been added. The |
| | | resulting request will have a ``registry`` attribute. It is meant to be |
| | | used in conjunction with ``pyramid.scripting.prepare`` and/or |
| | | ``pyramid.paster.bootstrap`` (both of which accept a request as an |
| | | argument):: |
| | | |
| | | from pyramid.scripting import make_request |
| | | request = make_request('/') |
| | | |
| | | - New API attribute ``pyramid.config.global_registries`` is an iterable |
| | | object that contains references to every Pyramid registry loaded into the |
| | | current process via ``pyramid.config.Configurator.make_app``. It also has |
| | | a ``last`` attribute containing the last registry loaded. This is used by |
| | | the scripting machinery, and is available for introspection. |
| | | |
| | | Deprecations |
| | | ------------ |
| | | |
| | | - The ``pyramid.view.static`` class has been deprecated in favor of the newer |
| | | ``pyramid.static.static_view`` class. A deprecation warning is raised when |
| | | it is used. You should replace it with a reference to |
| | | ``pyramid.static.static_view`` with the ``use_subpath=True`` argument. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - Without a mo-file loaded for the combination of domain/locale, |
| | | ``pyramid.i18n.Localizer.pluralize`` run using that domain/locale |
| | | combination raised an inscrutable "translations object has no attr |
| | | 'plural'" error. Now, instead it "works" (it uses a germanic pluralization |
| | | by default). It's nonsensical to try to pluralize something without |
| | | translations for that locale/domain available, but this behavior matches |
| | | the behavior of ``pyramid.i18n.Localizer.translate`` so it's at least |
| | | consistent; see https://github.com/Pylons/pyramid/issues/235. |
| | | |
| | | 1.1b2 (2011-07-13) |
| | | ================== |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - New environment setting ``PYRAMID_PREVENT_HTTP_CACHE`` and new |
| | | configuration file value ``prevent_http_cache``. These are synomymous and |
| | | allow you to prevent HTTP cache headers from being set by Pyramid's |
| | | ``http_cache`` machinery globally in a process. see the "Influencing HTTP |
| | | Caching" section of the "View Configuration" narrative chapter and the |
| | | detailed documentation for this setting in the "Environment Variables and |
| | | Configuration Settings" narrative chapter. |
| | | |
| | | Behavior Changes |
| | | ---------------- |
| | | |
| | | - Previously, If a ``BeforeRender`` event subscriber added a value via the |
| | | ``__setitem__`` or ``update`` methods of the event object with a key that |
| | | already existed in the renderer globals dictionary, a ``KeyError`` was |
| | | raised. With the deprecation of the "add_renderer_globals" feature of the |
| | | configurator, there was no way to override an existing value in the |
| | | renderer globals dictionary that already existed. Now, the event object |
| | | will overwrite an older value that is already in the globals dictionary |
| | | when its ``__setitem__`` or ``update`` is called (as well as the new |
| | | ``setdefault`` method), just like a plain old dictionary. As a result, for |
| | | maximum interoperability with other third-party subscribers, if you write |
| | | an event subscriber meant to be used as a BeforeRender subscriber, your |
| | | subscriber code will now need to (using ``.get`` or ``__contains__`` of the |
| | | event object) ensure no value already exists in the renderer globals |
| | | dictionary before setting an overriding value. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - The ``Configurator.add_route`` method allowed two routes with the same |
| | | route to be added without an intermediate ``config.commit()``. If you now |
| | | receive a ``ConfigurationError`` at startup time that appears to be |
| | | ``add_route`` related, you'll need to either a) ensure that all of your |
| | | route names are unique or b) call ``config.commit()`` before adding a |
| | | second route with the name of a previously added name or c) use a |
| | | Configurator that works in ``autocommit`` mode. |
| | | |
| | | - The ``pyramid_routesalchemy`` and ``pyramid_alchemy`` scaffolds |
| | | inappropriately used ``DBSession.rollback()`` instead of |
| | | ``transaction.abort()`` in one place. |
| | | |
| | | - We now clear ``request.response`` before we invoke an exception view; an |
| | | exception view will be working with a request.response that has not been |
| | | touched by any code prior to the exception. |
| | | |
| | | - Views associated with routes with spaces in the route name may not have |
| | | been looked up correctly when using Pyramid with ``zope.interface`` 3.6.4 |
| | | and better. See https://github.com/Pylons/pyramid/issues/232. |
| | | |
| | | Documentation |
| | | ------------- |
| | | |
| | | - Wiki2 (SQLAlchemy + URL Dispatch) tutorial ``models.initialize_sql`` didn't |
| | | match the ``pyramid_routesalchemy`` scaffold function of the same name; it |
| | | didn't get synchronized when it was changed in the scaffold. |
| | | |
| | | - New documentation section in View Configuration narrative chapter: |
| | | "Influencing HTTP Caching". |
| | | |
| | | 1.1b1 (2011-07-10) |
| | | ================== |
| | | |
| | | Features |
| | | -------- |
| | | |
| | | - It is now possible to invoke ``paster pshell`` even if the paste ini file |
| | | section name pointed to in its argument is not actually a Pyramid WSGI |
| | | application. The shell will work in a degraded mode, and will warn the |
| | | user. See "The Interactive Shell" in the "Creating a Pyramid Project" |
| | | narrative documentation section. |
| | | |
| | | - ``paster pshell`` now offers more built-in global variables by default |
| | | (including ``app`` and ``settings``). See "The Interactive Shell" in the |
| | | "Creating a Pyramid Project" narrative documentation section. |
| | | |
| | | - It is now possible to add a ``[pshell]`` section to your application's .ini |
| | | configuration file, which influences the global names available to a pshell |
| | | session. See "Extending the Shell" in the "Creating a Pyramid Project" |
| | | narrative documentation chapter. |
| | | |
| | | - The ``config.scan`` method has grown a ``**kw`` argument. ``kw`` argument |
| | | represents a set of keyword arguments to pass to the Venusian ``Scanner`` |
| | | object created by Pyramid. (See the Venusian documentation for more |
| | | information about ``Scanner``). |
| | | |
| | | - New request property: ``json_body``. This property will return the |
| | | JSON-decoded variant of the request body. If the request body is not |
| | | well-formed JSON, this property will raise an exception. |
| | | |
| | | - A new value ``http_cache`` can be used as a view configuration |
| | | parameter. |
| | |
| | | to only influence ``Cache-Control`` headers, pass a tuple as ``http_cache`` |
| | | with the first element of ``None``, e.g.: ``(None, {'public':True})``. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - Framework wrappers of the original view (such as http_cached and so on) |
| | | relied on being able to trust that the response they were receiving was an |
| | | IResponse. It wasn't always, because the response was resolved by the |
| | | router instead of early in the view wrapping process. This has been fixed. |
| | | |
| | | Documentation |
| | | ------------- |
| | | |
| | | - Added a section in the "Webob" chapter named "Dealing With A JSON-Encoded |
| | | Request Body" (usage of ``request.json_body``). |
| | | |
| | | Behavior Changes |
| | | ---------------- |
| | | |
| | | - The ``paster pshell``, ``paster proutes``, and ``paster pviews`` commands |
| | | now take a single argument in the form ``/path/to/config.ini#sectionname`` |
| | | rather than the previous 2-argument spelling ``/path/to/config.ini |
| | | sectionname``. ``#sectionname`` may be omitted, in which case ``#main`` is |
| | | assumed. |
| | | |
| | | 1.1a4 (2011-07-01) |
| | | ================== |
| | | |
| | |
| | | - Christoph Zwerschke, 2011/06/07 |
| | | |
| | | - Atsushi Odagiri, 2011/07/02 |
| | | |
| | | - Shane Hathaway, 2011/07/22 |
| | | |
| | | - Manuel Hermann, 2011/07/11 |
| | |
| | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| | | DAMAGE. |
| | | |
| | | Portions of the code in Pyramid are supplied under the Python Software |
| | | Foundation License version 2 (headers within individiual files indicate that |
| | | these portions are so licensed): |
| | | |
| | | PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 |
| | | -------------------------------------------- |
| | | |
| | | 1. This LICENSE AGREEMENT is between the Python Software Foundation |
| | | ("PSF"), and the Individual or Organization ("Licensee") accessing and |
| | | otherwise using this software ("Python") in source or binary form and |
| | | its associated documentation. |
| | | |
| | | 2. Subject to the terms and conditions of this License Agreement, PSF |
| | | hereby grants Licensee a nonexclusive, royalty-free, world-wide |
| | | license to reproduce, analyze, test, perform and/or display publicly, |
| | | prepare derivative works, distribute, and otherwise use Python |
| | | alone or in any derivative version, provided, however, that PSF's |
| | | License Agreement and PSF's notice of copyright, i.e., "Copyright (c) |
| | | 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; |
| | | All Rights Reserved" are retained in Python alone or in any derivative |
| | | version prepared by Licensee. |
| | | |
| | | 3. In the event Licensee prepares a derivative work that is based on |
| | | or incorporates Python or any part thereof, and wants to make |
| | | the derivative work available to others as provided herein, then |
| | | Licensee hereby agrees to include in any such work a brief summary of |
| | | the changes made to Python. |
| | | |
| | | 4. PSF is making Python available to Licensee on an "AS IS" |
| | | basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR |
| | | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND |
| | | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS |
| | | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT |
| | | INFRINGE ANY THIRD PARTY RIGHTS. |
| | | |
| | | 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON |
| | | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS |
| | | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, |
| | | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. |
| | | |
| | | 6. This License Agreement will automatically terminate upon a material |
| | | breach of its terms and conditions. |
| | | |
| | | 7. Nothing in this License Agreement shall be deemed to create any |
| | | relationship of agency, partnership, or joint venture between PSF and |
| | | Licensee. This License Agreement does not grant permission to use PSF |
| | | trademarks or trade name in a trademark sense to endorse or promote |
| | | products or services of Licensee, or any third party. |
| | | |
| | | 8. By copying, installing or otherwise using Python, Licensee |
| | | agrees to be bound by the terms and conditions of this License |
| | | Agreement. |
| | | |
| | | The documentation portion of Pyramid (the rendered contents of the |
| | | "docs" directory of a software distribution or checkout) is supplied |
| | | under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 |
| | |
| | | Releasing Pyramid |
| | | ================= |
| | | |
| | | - Make sure all unit tests pass and statement coverage is at 100%:: |
| | | - git pull |
| | | |
| | | - Do platform test via tox: |
| | | |
| | | $ tox |
| | | |
| | | - Make sure statement coverage is at 100%:: |
| | | |
| | | $ python setup.py nosetests --with-coverage |
| | | |
| | |
| | | |
| | | - Announce to Twitter. |
| | | |
| | | Announcement template |
| | | ---------------------- |
| | | |
| | | Pyramid 1.1.X has been released. |
| | | |
| | | Here are the changes: |
| | | |
| | | <<changes>> |
| | | |
| | | A "What's New In Pyramid 1.1" document exists at |
| | | http://docs.pylonsproject.org/projects/pyramid/1.1/whatsnew-1.1.html . |
| | | |
| | | You will be able to see the 1.1 release documentation (across all |
| | | alphas and betas, as well as when it eventually gets to final release) |
| | | at http://docs.pylonsproject.org/projects/pyramid/1.1/ . |
| | | |
| | | You can install it via PyPI: |
| | | |
| | | easy_install Pyramid==1.1a4 |
| | | |
| | | Enjoy, and please report any issues you find to the issue tracker at |
| | | https://github.com/Pylons/pyramid/issues |
| | | |
| | | Thanks! |
| | | |
| | | - C |
| | |
| | | Pyramid TODOs |
| | | ============= |
| | | |
| | | Must-Have |
| | | --------- |
| | | |
| | | - Github issues fixes. |
| | | |
| | | Should-Have |
| | | ----------- |
| | | |
| | | - BeforeRender event subclasses dict but implements a bunch of shit. Its |
| | | repr is currently broken (it always shows empty). Decide what to do. |
| | | |
| | | - Replace weberror for email-out in all production.ini. |
| | | |
| | | - Come up with an analogue of repoze.zodbconn that doesn't require a closer |
| | | in the pipeline and use it in the ZODB scaffold and tutorial. |
| | | |
| | | - Deprecate pyramid.security.view_execution_permitted (it only works for |
| | | traversal). |
| | | |
| | | - Make "localizer" a property of request (instead of requiring |
| | | "get_localizer(request)"? |
| | | "get_localizer(request)" |
| | | |
| | | - Investigate mod_wsgi tutorial to make sure it still works (2 reports say |
| | | no; application package not found). |
| | | - Make ``current_route_url`` a method of request. |
| | | |
| | | - Add narrative docs for wsgiapp and wsgiapp2. |
| | | - Create a ``current_route_path`` function and make it a method of request. |
| | | |
| | | - "static_path" API (omit host and port). |
| | | |
| | | - Provide a way to set the authentication policy and the authorization policy |
| | | during a config.include (they are related, so just exposing the currently |
| | | underscored-private _set_auth* methods won't cut it). |
| | | |
| | | - Try to figure out a way to keep "settings" as the original dictionary |
| | | passed to the Configurator instead of copying it. |
| | | |
| | | - Merge aodag's config.include(route_prefix=...) fork. |
| | | |
| | | - Merge Michael's route group work. |
| | | |
| | | - Kill off ``bfg.routes`` envvars in router. |
| | | |
| | | - Alias the stupid long default session factory name. |
| | | |
| | | - Fix indirect circular import between router and config. |
| | | |
| | | - Eliminate non-deployment-non-scaffold-related Paste dependencies: |
| | | ``paste.urlparser.StaticURLParser``, ``paste.auth.auth_tkt`` (cutnpaste or |
| | | reimplement both). |
| | | |
| | | Nice-to-Have |
| | | ------------ |
| | | |
| | | - Maybe add ``add_renderer_globals`` method to Configurator. |
| | | - Add narrative docs for wsgiapp and wsgiapp2. |
| | | |
| | | - Provide a ``has_view`` function. |
| | | |
| | | - Debug option to print view matching decision (e.g. debug_viewlookup or so). |
| | | |
| | | - Speed up startup time (defer _bootstrap and registerCommonDirectives() |
| | | until needed by ZCML, as well as unfound speedups). |
| | | |
| | | - Nicer Mako exceptions in WebError. |
| | | |
| | | - Response.RequestClass should probably be pyramid.request.Request but this |
| | | may imply actually subclassing webob.Response |
| | | - Nicer Mako exceptions in debug toolbar. |
| | | |
| | | - Better "Extending" chapter. |
| | | |
| | |
| | | |
| | | - Create a function which performs a recursive request. |
| | | |
| | | - Debug option to print view matching decision. |
| | | |
| | | - Update App engine chapter with less creaky directions. |
| | | |
| | | Probably Bad Ideas |
| | | ------------------ |
| | | |
| | | - Add functionality that mocks the behavior of ``repoze.browserid``. |
| | | |
| | |
| | | http://plope.com/pyramid_auth_design_api_postmortem, phasing out the |
| | | current auth-n-auth abstractions in a backwards compatible way. |
| | | |
| | | - Add doc string for BeforeRender event with more details. |
| | | - Maybe add ``add_renderer_globals`` method to Configurator. |
| | | |
| | |
| | | api/security |
| | | api/session |
| | | api/settings |
| | | api/static |
| | | api/testing |
| | | api/threadlocal |
| | | api/traversal |
| | | api/tweens |
| | | api/url |
| | | api/view |
| | | api/wsgi |
| | |
| | | |
| | | .. automethod:: add_route |
| | | |
| | | .. automethod:: add_static_view(name, path, cache_max_age=3600, permission='__no_permission_required__') |
| | | .. automethod:: add_static_view(name, path, cache_max_age=3600, permission=NO_PERMISSION_REQUIRED) |
| | | |
| | | .. automethod:: add_settings |
| | | |
| | |
| | | |
| | | .. automethod:: set_view_mapper |
| | | |
| | | .. automethod:: add_tween |
| | | |
| | | .. automethod:: testing_securitypolicy |
| | | |
| | | .. automethod:: testing_resources |
| | |
| | | |
| | | .. automethod:: testing_add_renderer |
| | | |
| | | .. attribute:: global_registries |
| | | |
| | | The set of registries that have been created for :app:`Pyramid` |
| | | applications, one per each call to |
| | | :meth:`pyramid.config.Configurator.make_wsgi_app` in the current |
| | | process. The object itself supports iteration and has a ``last`` |
| | | property containing the last registry loaded. |
| | | |
| | | The registries contained in this object are stored as weakrefs, |
| | | thus they will only exist for the lifetime of the actual |
| | | applications for which they are being used. |
| | | |
| | |
| | | ++++++++++++++++++++++++ |
| | | |
| | | .. autointerface:: IApplicationCreated |
| | | :members: |
| | | |
| | | .. autointerface:: INewRequest |
| | | :members: |
| | | |
| | | .. autointerface:: IContextFound |
| | | :members: |
| | | |
| | | .. autointerface:: INewResponse |
| | | :members: |
| | | |
| | | .. autointerface:: IBeforeRender |
| | | :members: |
| | | |
| | | Other Interfaces |
| | | ++++++++++++++++ |
| | |
| | | :mod:`pyramid.paster` |
| | | --------------------------- |
| | | |
| | | .. module:: pyramid.paster |
| | | .. automodule:: pyramid.paster |
| | | |
| | | .. function:: get_app(config_file, name) |
| | | .. function:: get_app(config_uri, name=None) |
| | | |
| | | Return the WSGI application named ``name`` in the PasteDeploy |
| | | config file ``config_file``. |
| | | Return the WSGI application named ``name`` in the PasteDeploy |
| | | config file specified by ``config_uri``. |
| | | |
| | | |
| | | If the ``name`` is None, this will attempt to parse the name from |
| | | the ``config_uri`` string expecting the format ``inifile#name``. |
| | | If no name is found, the name will default to "main". |
| | | |
| | | .. autofunction:: bootstrap |
| | |
| | | |
| | | .. autoclass:: JSONP |
| | | |
| | | .. attribute:: null_renderer |
| | | |
| | | An object that can be used in advanced integration cases as input to the |
| | | view configuration ``renderer=`` argument. When the null renderer is used |
| | | as a view renderer argument, Pyramid avoids converting the view callable |
| | | result into a Response object. This is useful if you want to reuse the |
| | | view configuration and lookup machinery outside the context of its use by |
| | | the Pyramid router (e.g. the package named ``pyramid_rpc`` does this). |
| | | |
| | |
| | | of ``request.exception`` will be ``None`` within response and |
| | | finished callbacks. |
| | | |
| | | .. attribute:: exc_info |
| | | |
| | | If an exception was raised by a :term:`root factory` or a :term:`view |
| | | callable`, or at various other points where :app:`Pyramid` executes |
| | | user-defined code during the processing of a request, result of |
| | | ``sys.exc_info()`` will be available as the ``exc_info`` attribute of |
| | | the request within a :term:`exception view`, a :term:`response callback` |
| | | or a :term:`finished callback`. If no exception occurred, the value of |
| | | ``request.exc_info`` will be ``None`` within response and finished |
| | | callbacks. |
| | | |
| | | .. attribute:: response |
| | | |
| | | This attribute is actually a "reified" property which returns an |
| | |
| | | object (exposed to view code as ``request.response``) to influence |
| | | rendered response behavior. |
| | | |
| | | .. attribute:: json |
| | | .. attribute:: json_body |
| | | |
| | | If the request's ``content_type`` is ``application/json``, this |
| | | attribute will contain the JSON-decoded variant of the request body. |
| | | If the request's ``content_type`` is not ``application/json``, this |
| | | attribute will be ``None``. |
| | | This property will return the JSON-decoded variant of the request |
| | | body. If the request body is not well-formed JSON, or there is no |
| | | body associated with this request, this property will raise an |
| | | exception. See also :ref:`request_json_body`. |
| | | |
| | | .. note:: |
| | | |
| | |
| | | :members: |
| | | :inherited-members: |
| | | |
| | | Functions |
| | | ~~~~~~~~~ |
| | | |
| | | .. autofunction:: response_adapter |
| | | |
| | |
| | | |
| | | .. autofunction:: get_root |
| | | |
| | | .. autofunction:: prepare |
| | | |
| | |
| | | last ACE in an ACL in systems that use an "inheriting" security |
| | | policy, representing the concept "don't inherit any other ACEs". |
| | | |
| | | .. attribute:: NO_PERMISSION_REQUIRED |
| | | |
| | | Return Values |
| | | ------------- |
| | | |
New file |
| | |
| | | .. _static_module: |
| | | |
| | | :mod:`pyramid.static` |
| | | --------------------- |
| | | |
| | | .. automodule:: pyramid.static |
| | | |
| | | .. autoclass:: static_view |
| | | :members: |
| | | :inherited-members: |
| | | |
New file |
| | |
| | | .. _tweens_module: |
| | | |
| | | :mod:`pyramid.tweens` |
| | | --------------------- |
| | | |
| | | .. automodule:: pyramid.tweens |
| | | |
| | | .. autofunction:: excview_tween_factory |
| | | |
| | | .. attribute:: MAIN |
| | | |
| | | Constant representing the main Pyramid handling function, for use in |
| | | ``under`` and ``over`` arguments to |
| | | :meth:`pyramid.config.Configurator.add_tween`. |
| | | |
| | | .. attribute:: INGRESS |
| | | |
| | | Constant representing the request ingress, for use in ``under`` and |
| | | ``over`` arguments to :meth:`pyramid.config.Configurator.add_tween`. |
| | | |
| | | .. attribute:: EXCVIEW |
| | | |
| | | Constant representing the exception view tween, for use in ``under`` |
| | | and ``over`` arguments to |
| | | :meth:`pyramid.config.Configurator.add_tween`. |
| | |
| | | single: Shipman, John |
| | | single: Beelby, Chris |
| | | single: Paez, Patricio |
| | | single: Merickel, Michael |
| | | |
| | | Thanks |
| | | ====== |
| | |
| | | Sawyers, Malthe Borch, Carlos de la Guardia, Chris Rossi, Shane Hathaway, |
| | | Daniel Holth, Wichert Akkerman, Georg Brandl, Blaise Laflamme, Ben Bangert, |
| | | Casey Duncan, Hugues Laflamme, Mike Orr, John Shipman, Chris Beelby, Patricio |
| | | Paez, Simon Oram, Nat Hardwick, Ian Bicking, Jim Fulton, Tom Moroz of the |
| | | Open Society Institute, and Todd Koym of Environmental Health Sciences. |
| | | Paez, Simon Oram, Nat Hardwick, Ian Bicking, Jim Fulton, Michael Merickel, |
| | | Tom Moroz of the Open Society Institute, and Todd Koym of Environmental |
| | | Health Sciences. |
| | | |
| | | Thanks to Guido van Rossum and Tim Peters for Python. |
| | | |
| | |
| | | # other places throughout the built documents. |
| | | # |
| | | # The short X.Y version. |
| | | version = '1.1a4' |
| | | version = '1.1' |
| | | # The full version, including alpha/beta/rc tags. |
| | | release = version |
| | | |
| | |
| | | Copyright, Trademarks, and Attributions |
| | | ======================================= |
| | | |
| | | *The Pyramid Web Application Development Framework, Version 1.0* |
| | | *The Pyramid Web Application Development Framework, Version 1.1* |
| | | |
| | | by Chris McDonough |
| | | |
| | |
| | | Ben Bangert, Blaise Laflamme, Rob Miller, Mike Orr, Carlos de la Guardia, |
| | | Paul Everitt, Tres Seaver, John Shipman, Marius Gedminas, Chris Rossi, |
| | | Joachim Krebs, Xavier Spriet, Reed O'Brien, William Chambers, Charlie |
| | | Choiniere, Jamaludin Ahmad, Graham Higgins, Patricio Paez. |
| | | Choiniere, Jamaludin Ahmad, Graham Higgins, Patricio Paez, Michael |
| | | Merickel, Eric Ongerth, Niall O'Higgins, Christoph Zwerschke, John |
| | | Anderson, Atsushi Odagiri, Kirk Strauser, JD Navarro, Joe Dallago, |
| | | Savoir-Faire Linux, Łukasz Fidosz, Christopher Lambacher, Claus Conrad, |
| | | Chris Beelby, and a number of people with only psuedonyms on GitHub. |
| | | |
| | | Cover Designer: |
| | | Hugues Laflamme of `Kemeneur <http://www.kemeneur.com/>`_. |
| | |
| | | |
| | | This is true. At the time of this writing, the total number of Python |
| | | package distributions that :app:`Pyramid` depends upon transitively is 18 if |
| | | you use Python 2.6 or 2.7, or 16 if you use Python 2.4 or 2.5. This is a lot |
| | | more than zero package distribution dependencies: a metric which various |
| | | Python microframeworks and Django boast. |
| | | you use Python 2.6 or 2.7, or 16 if you use Python 2.5. This is a lot more |
| | | than zero package distribution dependencies: a metric which various Python |
| | | microframeworks and Django boast. |
| | | |
| | | The :mod:`zope.component` and :mod:`zope.configuration` packages on which |
| | | :app:`Pyramid` depends have transitive dependencies on several other packages |
| | |
| | | <http://bobo.digicool.com/>`_ doesn't describe itself as a microframework, |
| | | but its intended userbase is much the same. Many others exist. We've |
| | | actually even (only as a teaching tool, not as any sort of official project) |
| | | `created one using BFG <http://bfg.repoze.org/videos#groundhog1>`_ (the |
| | | precursor to Pyramid). Microframeworks are small frameworks with one common |
| | | feature: each allows its users to create a fully functional application that |
| | | lives in a single Python file. |
| | | `created one using Pyramid <http://bfg.repoze.org/videos#groundhog1>`_ (the |
| | | videos use BFG, a precursor to Pyramid, but the resulting code is `available |
| | | for Pyramid too <http://github.com/Pylons/groundhog>`_). Microframeworks are |
| | | small frameworks with one common feature: each allows its users to create a |
| | | fully functional application that lives in a single Python file. |
| | | |
| | | Some developers and microframework authors point out that Pyramid's "hello |
| | | world" single-file program is longer (by about five lines) than the |
| | |
| | | a registry in another module. This has the effect that |
| | | double-registrations will never be performed. |
| | | |
| | | Routes (Usually) Need Relative Ordering |
| | | +++++++++++++++++++++++++++++++++++++++ |
| | | Routes Need Relative Ordering |
| | | +++++++++++++++++++++++++++++ |
| | | |
| | | Consider the following simple `Groundhog |
| | | <https://github.com/Pylons/groundhog>`_ application: |
| | |
| | | matches first. A 404 error is raised. This is not what we wanted; it just |
| | | happened due to the order in which we defined our view functions. |
| | | |
| | | You may be willing to maintain an ordering of your view functions which |
| | | reifies your routing policy. Your application may be small enough where this |
| | | will never cause an issue. If it becomes large enough to matter, however, I |
| | | don't envy you. Maintaining that ordering as your application grows larger |
| | | will be difficult. At some point, you will also need to start controlling |
| | | *import* ordering as well as function definition ordering. When your |
| | | application grows beyond the size of a single file, and when decorators are |
| | | used to register views, the non-``__main__`` modules which contain |
| | | configuration decorators must be imported somehow for their configuration to |
| | | be executed. |
| | | This is because "Groundhog" routes are added to the routing map in import |
| | | order, and matched in the same order when a request comes in. Bottle, like |
| | | Groundhog, as of this writing, matches routes in the order in which they're |
| | | defined at Python execution time. Flask, on the other hand, does not order |
| | | route matching based on import order; it reorders the routes you add to your |
| | | application based on their "complexity". Other microframeworks have varying |
| | | strategies to do route ordering. |
| | | |
| | | Does that make you a little uncomfortable? It should, because |
| | | Your application may be small enough where route ordering will never cause an |
| | | issue. If your application becomes large enough, however, being able to |
| | | specify or predict that ordering as your application grows larger will be |
| | | difficult. At some point, you will likely need to more explicitly start |
| | | controlling route ordering, especially in applications that require |
| | | extensibility. |
| | | |
| | | If your microframework orders route matching based on "complexity", you'll |
| | | need to understand what that "complexity" ordering is and attempt to inject a |
| | | "less complex" route to have it get matched before any "more complex" one to |
| | | ensure that it's tried first. |
| | | |
| | | If your microframework orders its route matching based on relative |
| | | import/execution of function decorator definitions, you will need to ensure |
| | | you execute all of these statements in the "right" order, and you'll need to |
| | | be cognizant of this import/execution ordering as you grow your application |
| | | or try to extend it. This is a difficult invariant to maintain for all but |
| | | the smallest applications. |
| | | |
| | | In either case, your application must import the non-``__main__`` modules |
| | | which contain configuration decorations somehow for their configuration to be |
| | | executed. Does that make you a little uncomfortable? It should, because |
| | | :ref:`you_dont_own_modulescope`. |
| | | |
| | | Pyramid uses neither decorator import time ordering nor does it attempt to |
| | | divine the relative "complexity" of one route to another in order to define a |
| | | route match ordering. In Pyramid, you have to maintain relative route |
| | | ordering imperatively via the chronology of multiple executions of the |
| | | :meth:`pyramid.config.Configurator.add_route` method. The order in which you |
| | | repeatedly call ``add_route`` becomes the order of route matching. |
| | | |
| | | If needing to maintain this imperative ordering truly bugs you, you can use |
| | | :term:`traversal` instead of route matching, which is a completely |
| | | declarative (and completely predictable) mechanism to map code to URLs. |
| | | While URL dispatch is easier to understand for small non-extensible |
| | | applications, traversal is a great fit for very large applications and |
| | | applications that need to be arbitrarily extensible. |
| | | |
| | | "Stacked Object Proxies" Are Too Clever / Thread Locals Are A Nuisance |
| | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| | |
| | | Pyramid has ~ 650 pages of documentation (printed), covering topics from the |
| | | very basic to the most advanced. *Nothing* is left undocumented, quite |
| | | literally. It also has an *awesome*, very helpful community. Visit the |
| | | #repoze and/or #pylons IRC channels on freenode.net and see. |
| | | #pyramid and/or #pylons IRC channels on freenode.net and see. |
| | | |
| | | Hate Zope |
| | | +++++++++ |
| | |
| | | a subclass such as :class:`pyramid.httpexceptions.HTTPFound`. See |
| | | :ref:`webob_chapter` for information about response objects. |
| | | |
| | | response adapter |
| | | A callable which accepts an arbitrary object and "converts" it to a |
| | | :class:`pyramid.response.Response` object. See :ref:`using_iresponse` |
| | | for more information. |
| | | |
| | | Repoze |
| | | "Repoze" is essentially a "brand" of software developed by `Agendaless |
| | | Consulting <http://agendaless.com>`_ and a set of contributors. The |
| | |
| | | :term:`ZODB` database. |
| | | |
| | | WebOb |
| | | `WebOb <http://pythonpaste.org/webob/>`_ is a WSGI request/response |
| | | `WebOb <http://webob.org>`_ is a WSGI request/response |
| | | library created by Ian Bicking. |
| | | |
| | | Paste |
| | |
| | | `JavaScript Object Notation <http://www.json.org/>`_ is a data |
| | | serialization format. |
| | | |
| | | jQuery |
| | | A popular `Javascript library <http://jquery.org>`_. |
| | | |
| | | renderer |
| | | A serializer that can be referred to via :term:`view |
| | | configuration` which converts a non-:term:`Response` return |
| | |
| | | declaration` required by your application. |
| | | |
| | | declarative configuration |
| | | The configuration mode in which you use :term:`ZCML` to make a set of |
| | | :term:`configuration declaration` statements. See :term:`pyramid_zcml`. |
| | | The configuration mode in which you use the combination of |
| | | :term:`configuration decoration` and a :term:`scan` to configure your |
| | | Pyramid application. |
| | | |
| | | Not Found view |
| | | An :term:`exception view` invoked by :app:`Pyramid` when the |
| | |
| | | A :term:`response` that is generated as the result of a raised exception |
| | | being caught by an :term:`exception view`. |
| | | |
| | | PyPy |
| | | PyPy is an "alternative implementation of the Python |
| | | language":http://pypy.org/ |
| | | |
| | | tween |
| | | A bit of code that sits between the Pyramid router's main request |
| | | handling function and the upstream WSGI component that uses |
| | | :app:`Pyramid` as its 'app'. The word "tween" is a contraction of |
| | | "between". A tween may be used by Pyramid framework extensions, to |
| | | provide, for example, Pyramid-specific view timing support, bookkeeping |
| | | code that examines exceptions before they are returned to the upstream |
| | | WSGI application, or a variety of other features. Tweens behave a bit |
| | | like :mod:`WSGI` 'middleware' but they have the benefit of running in a |
| | | context in which they have access to the Pyramid :term:`application |
| | | registry` as well as the Pyramid rendering machinery. See |
| | | :ref:`registering_tweens`. |
| | | |
| | |
| | | .. toctree:: |
| | | :maxdepth: 1 |
| | | |
| | | whatsnew-1.0 |
| | | whatsnew-1.1 |
| | | whatsnew-1.0 |
| | | |
| | | Narrative documentation |
| | | ======================= |
| | |
| | | narr/project |
| | | narr/startup |
| | | narr/urldispatch |
| | | narr/muchadoabouttraversal |
| | | narr/traversal |
| | | narr/views |
| | | narr/renderers |
| | | narr/templates |
| | | narr/viewconfig |
| | | narr/resources |
| | | narr/assets |
| | | narr/webob |
| | | narr/sessions |
| | | narr/security |
| | | narr/hybrid |
| | | narr/i18n |
| | | narr/vhosting |
| | | narr/events |
| | | narr/environment |
| | | narr/commandline |
| | | narr/i18n |
| | | narr/vhosting |
| | | narr/testing |
| | | narr/resources |
| | | narr/muchadoabouttraversal |
| | | narr/traversal |
| | | narr/security |
| | | narr/hybrid |
| | | narr/hooks |
| | | narr/advconfig |
| | | narr/extending |
| | |
| | | narr/firstapp |
| | | narr/project |
| | | narr/urldispatch |
| | | narr/muchadoabouttraversal |
| | | narr/traversal |
| | | narr/views |
| | | narr/renderers |
| | | narr/templates |
| | | narr/viewconfig |
| | | narr/resources |
| | | narr/assets |
| | | narr/webob |
| | | narr/sessions |
| | | narr/security |
| | | narr/hybrid |
| | | narr/i18n |
| | | narr/vhosting |
| | | narr/events |
| | | narr/environment |
| | | narr/commandline |
| | | narr/i18n |
| | | narr/vhosting |
| | | narr/testing |
| | | narr/resources |
| | | narr/muchadoabouttraversal |
| | | narr/traversal |
| | | narr/security |
| | | narr/hybrid |
| | | narr/hooks |
| | | narr/advconfig |
| | | narr/extending |
| | |
| | | #!/bin/sh |
| | | make clean latex SPHINXBUILD=../bookenv/bin/sphinx-build BOOK=1 |
| | | make clean latex SPHINXBUILD=../env26/bin/sphinx-build BOOK=1 |
| | | cd _build/latex && make all-pdf |
| | | |
New file |
| | |
| | | #!/bin/sh |
| | | make clean epub SPHINXBUILD=../env26/bin/sphinx-build |
New file |
| | |
| | | #!/bin/sh |
| | | make clean latex SPHINXBUILD=../env26/bin/sphinx-build |
| | | cd _build/latex && make all-pdf |
| | | |
| | |
| | | [app:MyProject] |
| | | use = egg:MyProject |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | MyProject |
| | | |
| | | [server:main] |
| | |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" |
| | | action="http://docs.pylonsproject.org/pyramid/dev/search.html"> |
| | | action="http://docs.pylonsproject.org/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | </a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation"> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation"> |
| | | Narrative Documentation |
| | | </a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation"> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation"> |
| | | API Documentation |
| | | </a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials"> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials"> |
| | | Tutorials |
| | | </a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history"> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history"> |
| | | Change History |
| | | </a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications"> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications"> |
| | | Sample Applications |
| | | </a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development"> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development"> |
| | | Support and Development |
| | | </a> |
| | | </li> |
| | |
| | | [app:MyProject] |
| | | use = egg:MyProject |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | |
| | | [filter:weberror] |
| | | use = egg:WebError#error_catcher |
| | |
| | | README = open(os.path.join(here, 'README.txt')).read() |
| | | CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() |
| | | |
| | | requires = ['pyramid', 'WebError'] |
| | | requires = ['pyramid', 'pyramid_debugtoolbar', 'WebError'] |
| | | |
| | | setup(name='MyProject', |
| | | version='0.0', |
| | |
| | | circumstances. |
| | | |
| | | .. index:: |
| | | single: imperative configuration |
| | | pair: configuration; conflict detection |
| | | |
| | | .. _conflict_detection: |
| | | |
| | |
| | | provides conflict detection, because it's implemented in terms of the |
| | | conflict-aware ``add_route`` and ``add_view`` methods. |
| | | |
| | | .. index:: |
| | | pair: configuration; including from external sources |
| | | |
| | | .. _including_configuration: |
| | | |
| | | Including Configuration from External Sources |
| | |
| | | constraints are not absolved by two-phase configuration. Routes are still |
| | | added in configuration execution order. |
| | | |
| | | .. index:: |
| | | single: add_directive |
| | | pair: configurator; adding directives |
| | | |
| | | .. _add_directive: |
| | | |
| | | Adding Methods to the Configurator via ``add_directive`` |
| | |
| | | ``.css``, ``.js``, and ``.gif`` files. These asset files are delivered when |
| | | a user visits an application URL. |
| | | |
| | | .. index:: |
| | | single: asset specifications |
| | | |
| | | .. _asset_specifications: |
| | | |
| | | Understanding Asset Specifications |
| | |
| | | |
| | | .. index:: |
| | | single: add_static_view |
| | | pair: assets; serving |
| | | |
| | | .. _static_assets_section: |
| | | |
| | |
| | | .. index:: |
| | | single: generating static asset urls |
| | | single: static asset urls |
| | | pair: assets; generating urls |
| | | |
| | | .. _generating_static_asset_urls: |
| | | |
| | |
| | | Root-Relative Custom Static View (URL Dispatch Only) |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | The :class:`pyramid.view.static` helper class generates a Pyramid view |
| | | The :class:`pyramid.static.static_view` helper class generates a Pyramid view |
| | | callable. This view callable can serve static assets from a directory. An |
| | | instance of this class is actually used by the |
| | | :meth:`~pyramid.config.Configurator.add_static_view` configuration method, so |
| | |
| | | exclusively. The root-relative route we'll be registering will always be |
| | | matched before traversal takes place, subverting any views registered via |
| | | ``add_view`` (at least those without a ``route_name``). A |
| | | :class:`~pyramid.view.static` static view cannot be made root-relative when |
| | | you use traversal. |
| | | :class:`~pyramid.static.static_view` static view cannot be made |
| | | root-relative when you use traversal unless it's registered as a |
| | | :term:`Not Found view`. |
| | | |
| | | To serve files within a directory located on your filesystem at |
| | | ``/path/to/static/dir`` as the result of a "catchall" route hanging from the |
| | | root that exists at the end of your routing table, create an instance of the |
| | | :class:`~pyramid.view.static` class inside a ``static.py`` file in your |
| | | application root as below. |
| | | :class:`~pyramid.static.static_view` class inside a ``static.py`` file in |
| | | your application root as below. |
| | | |
| | | .. ignore-next-block |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.view import static |
| | | static_view = static('/path/to/static/dir') |
| | | from pyramid.static import static |
| | | static_view = static_view('/path/to/static/dir', use_subpath=True) |
| | | |
| | | .. note:: For better cross-system flexibility, use an :term:`asset |
| | | specification` as the argument to :class:`~pyramid.view.static` instead of |
| | | a physical absolute filesystem path, e.g. ``mypackage:static`` instead of |
| | | ``/path/to/mypackage/static``. |
| | | specification` as the argument to :class:`~pyramid.static.static_view` |
| | | instead of a physical absolute filesystem path, e.g. ``mypackage:static`` |
| | | instead of ``/path/to/mypackage/static``. |
| | | |
| | | Subsequently, you may wire the files that are served by this view up to be |
| | | accessible as ``/<filename>`` using a configuration method in your |
| | |
| | | config.add_view('myapp.static.static_view', route_name='catchall_static') |
| | | |
| | | The special name ``*subpath`` above is used by the |
| | | :class:`~pyramid.view.static` view callable to signify the path of the file |
| | | relative to the directory you're serving. |
| | | :class:`~pyramid.static.static_view` view callable to signify the path of the |
| | | file relative to the directory you're serving. |
| | | |
| | | Registering A View Callable to Serve a "Static" Asset |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | - A directory containing multiple Chameleon templates. |
| | | |
| | | - Individual static files served up by an instance of the |
| | | ``pyramid.view.static`` helper class. |
| | | ``pyramid.static.static_view`` helper class. |
| | | |
| | | - A directory of static files served up by an instance of the |
| | | ``pyramid.view.static`` helper class. |
| | | ``pyramid.static.static_view`` helper class. |
| | | |
| | | - Any other asset (or set of assets) addressed by code that uses the |
| | | setuptools :term:`pkg_resources` API. |
New file |
| | |
| | | .. _command_line_chapter: |
| | | |
| | | Command-Line Pyramid |
| | | ==================== |
| | | |
| | | Your :app:`Pyramid` application can be controlled and inspected using a |
| | | variety of command-line utilities. These utilities are documented in this |
| | | chapter. |
| | | |
| | | .. index:: |
| | | pair: matching views; printing |
| | | single: paster pviews |
| | | |
| | | .. _displaying_matching_views: |
| | | |
| | | Displaying Matching Views for a Given URL |
| | | ----------------------------------------- |
| | | |
| | | For a big application with several views, it can be hard to keep the view |
| | | configuration details in your head, even if you defined all the views |
| | | yourself. You can use the ``paster pviews`` command in a terminal window to |
| | | print a summary of matching routes and views for a given URL in your |
| | | application. The ``paster pviews`` command accepts two arguments. The first |
| | | argument to ``pviews`` is the path to your application's ``.ini`` file and |
| | | section name inside the ``.ini`` file which points to your application. This |
| | | should be of the format ``config_file#section_name``. The second argument is |
| | | the URL to test for matching views. The ``section_name`` may be omitted; if |
| | | it is, it's considered to be ``main``. |
| | | |
| | | Here is an example for a simple view configuration using :term:`traversal`: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | $ ../bin/paster pviews development.ini#tutorial /FrontPage |
| | | |
| | | URL = /FrontPage |
| | | |
| | | context: <tutorial.models.Page object at 0xa12536c> |
| | | view name: |
| | | |
| | | 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 view matches, so there is just a single *View* section. For each |
| | | matching view, the full code path to the associated view callable is shown, |
| | | along with any permissions and predicates that are part of that view |
| | | configuration. |
| | | |
| | | A more complex configuration might generate something like this: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | $ ../bin/paster 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 |
| | | displayed first, followed by any views that are associated with that route. |
| | | As you can see from the second matching route output, a route can be |
| | | associated with more than one view. |
| | | |
| | | For a URL that doesn't match any views, ``paster pviews`` will simply print |
| | | out a *Not found* message. |
| | | |
| | | |
| | | .. index:: |
| | | single: interactive shell |
| | | single: IPython |
| | | single: paster pshell |
| | | single: pshell |
| | | |
| | | .. _interactive_shell: |
| | | |
| | | The Interactive Shell |
| | | --------------------- |
| | | |
| | | Once you've installed your program for development using ``setup.py |
| | | develop``, you can use an interactive Python shell to execute expressions in |
| | | a Python environment exactly like the one that will be used when your |
| | | application runs "for real". To do so, use the ``paster pshell`` command. |
| | | |
| | | The argument to ``pshell`` follows the format ``config_file#section_name`` |
| | | where ``config_file`` is the path to your application's ``.ini`` file and |
| | | ``section_name`` is the ``app`` section name inside the ``.ini`` file which |
| | | points to your application. For example, if your application ``.ini`` file |
| | | might have a ``[app:MyProject]`` section that looks like so: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [app:MyProject] |
| | | 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 ``MyProject`` as a section name: |
| | | |
| | | .. code-block:: text |
| | | |
| | | chrism@thinko env26]$ bin/paster pshell starter/development.ini#MyProject |
| | | Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32) |
| | | [GCC 4.4.3] on linux2 |
| | | Type "help" for more information. |
| | | |
| | | Environment: |
| | | app The WSGI application. |
| | | registry Active Pyramid registry. |
| | | request Active request object. |
| | | root Root of the default resource tree. |
| | | root_factory Default root factory used to create `root`. |
| | | >>> root |
| | | <myproject.resources.MyResource object at 0x445270> |
| | | >>> registry |
| | | <Registry myproject> |
| | | >>> registry.settings['pyramid.debug_notfound'] |
| | | False |
| | | >>> from myproject.views import my_view |
| | | >>> from pyramid.request import Request |
| | | >>> r = Request.blank('/') |
| | | >>> my_view(r) |
| | | {'project': 'myproject'} |
| | | |
| | | The WSGI application that is loaded will be available in the shell as the |
| | | ``app`` global. Also, if the application that is loaded is the :app:`Pyramid` |
| | | app with no surrounding middleware, the ``root`` object returned by the |
| | | default :term:`root factory`, ``registry``, and ``request`` will be |
| | | available. |
| | | |
| | | You can also simply rely on the ``main`` default section name by omitting any |
| | | hash after the filename: |
| | | |
| | | .. code-block:: text |
| | | |
| | | chrism@thinko env26]$ bin/paster pshell starter/development.ini |
| | | |
| | | Press ``Ctrl-D`` to exit the interactive shell (or ``Ctrl-Z`` on Windows). |
| | | |
| | | .. index:: |
| | | pair: pshell; extending |
| | | |
| | | .. _extending_pshell: |
| | | |
| | | Extending the Shell |
| | | ~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | It is sometimes convenient when using the interactive shell often to have |
| | | some variables significant to your application already loaded as globals when |
| | | you start the ``pshell``. To facilitate this, ``pshell`` will look for a |
| | | special ``[pshell]`` section in your INI file and expose the subsequent |
| | | key/value pairs to the shell. Each key is a variable name that will be |
| | | global within the pshell session; each value is a :term:`dotted Python name`. |
| | | |
| | | For example, you want to expose your model to the shell, along with the |
| | | database session so that you can mutate the model on an actual database. |
| | | Here, we'll assume your model is stored in the ``myapp.models`` package. |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [pshell] |
| | | m = myapp.models |
| | | session = myapp.models.DBSession |
| | | t = transaction |
| | | |
| | | When this INI file is loaded, the extra variables ``m``, ``session`` and |
| | | ``t`` will be available for use immediately. For example: |
| | | |
| | | .. code-block:: text |
| | | |
| | | chrism@thinko env26]$ bin/paster 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. |
| | | |
| | | Environment: |
| | | app The WSGI application. |
| | | registry Active Pyramid registry. |
| | | request Active request object. |
| | | root Root of the default resource tree. |
| | | root_factory Default root factory used to create `root`. |
| | | |
| | | Custom Variables: |
| | | m myapp.models |
| | | session myapp.models.DBSession |
| | | t transaction |
| | | >>> |
| | | |
| | | .. index:: |
| | | single: IPython |
| | | |
| | | IPython |
| | | ~~~~~~~ |
| | | |
| | | If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ installed in |
| | | the interpreter you use to invoke the ``paster`` command, the ``pshell`` |
| | | command will use an IPython interactive shell instead of a standard Python |
| | | interpreter shell. If you don't want this to happen, even if you have |
| | | IPython installed, you can pass the ``--disable-ipython`` flag to the |
| | | ``pshell`` command to use a standard Python interpreter shell |
| | | unconditionally. |
| | | |
| | | .. code-block:: text |
| | | |
| | | [chrism@vitaminf shellenv]$ ../bin/paster pshell --disable-ipython \ |
| | | development.ini#MyProject |
| | | |
| | | |
| | | .. index:: |
| | | pair: routes; printing |
| | | single: paster proutes |
| | | single: proutes |
| | | |
| | | .. _displaying_application_routes: |
| | | |
| | | Displaying All Application Routes |
| | | --------------------------------- |
| | | |
| | | You can use the ``paster proutes`` command in a terminal window to print a |
| | | summary of routes related to your application. Much like the ``paster |
| | | pshell`` command (see :ref:`interactive_shell`), the ``paster proutes`` |
| | | command accepts one argument with the format ``config_file#section_name``. |
| | | The ``config_file`` is the path to your application's ``.ini`` file, and |
| | | ``section_name`` is the ``app`` section name inside the ``.ini`` file which |
| | | points to your application. By default, the ``section_name`` is ``main`` and |
| | | can be omitted. |
| | | |
| | | For example: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [chrism@thinko MyProject]$ ../bin/paster proutes development.ini#MyProject |
| | | Name Pattern View |
| | | ---- ------- ---- |
| | | home / <function my_view> |
| | | home2 / <function my_view> |
| | | another /another None |
| | | static/ static/*subpath <static_view object> |
| | | catchall /*subpath <function static_view> |
| | | |
| | | ``paster proutes`` generates a table. The table has three columns: a Name |
| | | column, a Pattern column, and a View column. The items listed in the |
| | | Name column are route names, the items listed in the Pattern column are route |
| | | patterns, and the items listed in the View column are representations of the |
| | | view callable that will be invoked when a request matches the associated |
| | | route pattern. The view column may show ``None`` if no associated view |
| | | callable could be found. If no routes are configured within your |
| | | application, nothing will be printed to the console when ``paster proutes`` |
| | | is executed. |
| | | |
| | | .. index:: |
| | | pair: tweens; printing |
| | | single: paster ptweens |
| | | single: ptweens |
| | | |
| | | .. _displaying_tweens: |
| | | |
| | | Displaying "Tweens" |
| | | ------------------- |
| | | |
| | | A :term:`tween` is a bit of code that sits between the main Pyramid |
| | | application request handler and the WSGI application which calls it. A user |
| | | can get a representation of both the implicit tween ordering (the ordering |
| | | specified by calls to :meth:`pyramid.config.Configurator.add_tween`) and the |
| | | explicit tween ordering (specified by the ``pyramid.tweens`` configuration |
| | | setting) orderings using the ``paster ptweens`` command. Handler factories |
| | | which are functions or classes will show up as a standard Python dotted name |
| | | in the ``paster ptweens`` output. Tween factories which are *instances* will |
| | | show their module and class name; the Python object id of the instance will |
| | | be appended. |
| | | |
| | | For example, here's the ``paster pwteens`` command run against a system |
| | | configured without any explicit tweens: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [chrism@thinko pyramid]$ paster ptweens development.ini |
| | | "pyramid.tweens" config value NOT set (implicitly ordered tweens used) |
| | | |
| | | Implicit Tween Chain |
| | | |
| | | Position Name Alias |
| | | -------- ---- ----- |
| | | - - INGRESS |
| | | 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory pdbt |
| | | 1 pyramid.tweens.excview_tween_factory excview |
| | | - - MAIN |
| | | |
| | | Here's the ``paster pwteens`` command run against a system configured *with* |
| | | explicit tweens defined in its ``development.ini`` file: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [chrism@thinko pyramid]$ paster ptweens development.ini |
| | | "pyramid.tweens" config value set (explicitly ordered tweens used) |
| | | |
| | | Explicit Tween Chain (used) |
| | | |
| | | Position Name |
| | | -------- ---- |
| | | - INGRESS |
| | | 0 starter.tween_factory2 |
| | | 1 starter.tween_factory1 |
| | | 2 pyramid.tweens.excview_tween_factory |
| | | - MAIN |
| | | |
| | | Implicit Tween Chain (not used) |
| | | |
| | | Position Name Alias |
| | | -------- ---- ----- |
| | | - - INGRESS |
| | | 0 pyramid_debugtoolbar.toolbar.toolbar_tween_factory pdbt |
| | | 1 pyramid.tweens.excview_tween_factory excview |
| | | - - MAIN |
| | | |
| | | Here's the application configuration section of the ``development.ini`` used |
| | | by the above ``paster ptweens`` command which reprorts that the explicit |
| | | tween chain is used: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [app:starter] |
| | | 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. |
| | | |
| | | .. _writing_a_script: |
| | | |
| | | Writing a Script |
| | | ---------------- |
| | | |
| | | All web applications are, at their hearts, systems which accept a request and |
| | | return a response. When a request is accepted by a :app:`Pyramid` |
| | | application, the system receives state from the request which is later relied |
| | | on by your application code. For example, one :term:`view callable` may assume |
| | | it's working against a request that has a ``request.matchdict`` of a |
| | | particular composition, while another assumes a different composition of the |
| | | matchdict. |
| | | |
| | | In the meantime, it's convenient to be able to write a Python script that can |
| | | work "in a Pyramid environment", for instance to update database tables used |
| | | by your :app:`Pyramid` application. But a "real" Pyramid environment doesn't |
| | | have a completely static state independent of a request; your application |
| | | (and Pyramid itself) is almost always reliant on being able to obtain |
| | | information from a request. When you run a Python script that simply imports |
| | | code from your application and tries to run it, there just is no request |
| | | data, because there isn't any real web request. Therefore some parts of your |
| | | application and some Pyramid APIs will not work. |
| | | |
| | | For this reason, :app:`Pyramid` makes it possible to run a script in an |
| | | environment much like the environment produced when a particular |
| | | :term:`request` reaches your :app:`Pyramid` application. This is achieved by |
| | | using the :func:`pyramid.paster.bootstrap` command in the body of your |
| | | script. |
| | | |
| | | .. note:: This feature is new as of :app:`Pyramid` 1.1. |
| | | |
| | | In the simplest case, :func:`pyramid.paster.bootstrap` can be used with a |
| | | single argument, which accepts the :term:`PasteDeploy` ``.ini`` file |
| | | representing Pyramid your application configuration as a single argument: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.paster import bootstrap |
| | | env = bootstrap('/path/to/my/development.ini') |
| | | print env['request'].route_url('home') |
| | | |
| | | :func:`pyramid.paster.bootstrap` returns a dictionary containing |
| | | framework-related information. This dictionary will always contain a |
| | | :term:`request` object as its ``request`` key. |
| | | |
| | | The following keys are available in the ``env`` dictionary returned by |
| | | :func:`pyramid.paster.bootstrap`: |
| | | |
| | | request |
| | | |
| | | A :class:`pyramid.request.Request` object implying the current request |
| | | state for your script. |
| | | |
| | | app |
| | | |
| | | The :term:`WSGI` application object generated by bootstrapping. |
| | | |
| | | root |
| | | |
| | | The :term:`resource` root of your :app:`Pyramid` application. This is an |
| | | object generated by the :term:`root factory` configured in your |
| | | application. |
| | | |
| | | registry |
| | | |
| | | The :term:`application registry` of your :app:`Pyramid` application. |
| | | |
| | | closer |
| | | |
| | | A parameterless callable that can be used to pop an internal |
| | | :app:`Pyramid` threadlocal stack (used by |
| | | :func:`pyramid.threadlocal.get_current_registry` and |
| | | :func:`pyramid.threadlocal.get_current_request`) when your scripting job |
| | | is finished. |
| | | |
| | | Let's assume that the ``/path/to/my/development.ini`` file used in the |
| | | example above looks like so: |
| | | |
| | | .. code-block:: ini |
| | | |
| | | [pipeline:main] |
| | | pipeline = egg:WebError#evalerror |
| | | another |
| | | |
| | | [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 file by default. Specifying ``/path/to/my/development.ini`` is |
| | | logically equivalent to specifying ``/path/to/my/development.ini#main``. In |
| | | this case, we'll be using a configuration that includes an ``app`` object |
| | | which is wrapped in the WebError ``evalerror`` middleware. |
| | | |
| | | You can also specify a particular *section* of the PasteDeploy ``.ini`` file |
| | | to load instead of ``main``: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.paster import bootstrap |
| | | env = bootstrap('/path/to/my/development.ini#another') |
| | | print env['request'].route_url('home') |
| | | |
| | | The above example specifies the ``another`` ``app``, ``pipeline``, or |
| | | ``composite`` section of your PasteDeploy configuration file. The ``app`` |
| | | object present in the ``env`` dictionary returned by |
| | | :func:`pyramid.paster.bootstrap` will be a :app:`Pyramid` :term:`router`. |
| | | |
| | | Changing the Request |
| | | ~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | By default, Pyramid will generate a request object in the ``env`` dictionary |
| | | for the URL ``http://localhost:80/``. This means that any URLs generated |
| | | by Pyramid during the execution of your script will be anchored here. This |
| | | is generally not what you want. |
| | | |
| | | So how do we make Pyramid generate the correct URLs? |
| | | |
| | | Assuming that you have a route configured in your application like so: |
| | | |
| | | .. code-block:: python |
| | | |
| | | 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 mount our |
| | | application at `example.com/prefix` and the generated URLs should use HTTPS. |
| | | This can be done by mutating the request object: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.paster import bootstrap |
| | | env = bootstrap('/path/to/my/development.ini#another') |
| | | env['request'].host = 'example.com' |
| | | env['request'].scheme = 'https' |
| | | env['request'].script_name = '/prefix' |
| | | print env['request'].application_url |
| | | # will print 'https://example.com/prefix/another/url' |
| | | |
| | | Now you can readily use Pyramid's APIs for generating URLs: |
| | | |
| | | .. code-block:: python |
| | | |
| | | route_url('verify', env['request'], code='1337') |
| | | # will return 'https://example.com/prefix/verify/1337' |
| | | |
| | | Cleanup |
| | | ~~~~~~~ |
| | | |
| | | When your scripting logic finishes, it's good manners (but not required) to |
| | | call the ``closer`` callback: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.paster import bootstrap |
| | | env = bootstrap('/path/to/my/development.ini') |
| | | |
| | | # .. do stuff ... |
| | | |
| | | env['closer']() |
| | | |
| | | Setting Up Logging |
| | | ~~~~~~~~~~~~~~~~~~ |
| | | |
| | | By default, :func:`pyramid.paster.bootstrap` does not configure logging |
| | | parameters present in the configuration file. If you'd like to configure |
| | | logging based on ``[logger]`` and related sections in the configuration file, |
| | | use the following command: |
| | | |
| | | .. code-block:: python |
| | | |
| | | import logging |
| | | logging.fileConfig('/path/to/my/development.ini') |
| | |
| | | Application Configuration |
| | | ========================= |
| | | |
| | | Each deployment of an application written using :app:`Pyramid` implies a |
| | | specific *configuration* of the framework itself. For example, an |
| | | application which serves up MP3 files for your listening enjoyment might plug |
| | | code into the framework that manages song files, while an application that |
| | | manages corporate data might plug in code that manages accounting |
| | | information. The way in which code is plugged in to :app:`Pyramid` for a |
| | | specific application is referred to as "configuration". |
| | | Most people already understand "configuration" as settings that influence the |
| | | operation of an application. For instance, it's easy to think of the values |
| | | in a ``.ini`` file parsed at application startup time as "configuration". |
| | | However, if you're reasonably open-minded, it's easy to think of *code* as |
| | | configuration too. Since Pyramid, like most other web application platforms, |
| | | is a *framework*, it calls into code that you write (as opposed to a |
| | | *library*, which is code that exists purely for you to call). The act of |
| | | plugging application code that you've written into :app:`Pyramid` is also |
| | | referred to within this documentation as "configuration"; you are configuring |
| | | :app:`Pyramid` to call the code that makes up your application. |
| | | |
| | | Most people understand "configuration" as coarse settings that inform the |
| | | high-level operation of a specific application deployment. For instance, |
| | | it's easy to think of the values implied by a ``.ini`` file parsed at |
| | | application startup time as "configuration". :app:`Pyramid` extends this |
| | | pattern to application development, using the term "configuration" to express |
| | | standardized ways that code gets plugged into a deployment of the framework |
| | | itself. When you plug code into the :app:`Pyramid` framework, you are |
| | | "configuring" :app:`Pyramid` to create a particular application. |
| | | There are two ways to configure a :app:`Pyramid` application: |
| | | :term:`imperative configuration` and :term:`declarative configuration`. Both |
| | | are described below. |
| | | |
| | | .. index:: |
| | | single: imperative configuration |
| | |
| | | Imperative Configuration |
| | | ------------------------ |
| | | |
| | | Here's one of the simplest :app:`Pyramid` applications, configured |
| | | imperatively: |
| | | "Imperative configuration" just means configuration done by Python |
| | | statements, one after the next. Here's one of the simplest :app:`Pyramid` |
| | | applications, configured imperatively: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | .. _decorations_and_code_scanning: |
| | | |
| | | Configuration Decorations and Code Scanning |
| | | ------------------------------------------- |
| | | Declarative Configuration |
| | | ------------------------- |
| | | |
| | | A different mode of configuration gives more *locality of reference* to a |
| | | :term:`configuration declaration`. It's sometimes painful to have all |
| | | configuration done in imperative code, because often the code for a single |
| | | application may live in many files. If the configuration is centralized in |
| | | one place, you'll need to have at least two files open at once to see the |
| | | "big picture": the file that represents the configuration, and the file that |
| | | contains the implementation objects referenced by the configuration. To |
| | | avoid this, :app:`Pyramid` allows you to insert :term:`configuration |
| | | decoration` statements very close to code that is referred to by the |
| | | declaration itself. For example: |
| | | It's sometimes painful to have all configuration done by imperative code, |
| | | because often the code for a single application may live in many files. If |
| | | the configuration is centralized in one place, you'll need to have at least |
| | | two files open at once to see the "big picture": the file that represents the |
| | | configuration, and the file that contains the implementation objects |
| | | referenced by the configuration. To avoid this, :app:`Pyramid` allows you to |
| | | insert :term:`configuration decoration` statements very close to code that is |
| | | referred to by the declaration itself. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | behalf: these calls replace the need to add imperative configuration |
| | | statements that don't live near the code being configured. |
| | | |
| | | The combination of :term:`configuration decoration` and the invocation of a |
| | | :term:`scan` is collectively known as :term:`declarative configuration`. |
| | | |
| | | In the example above, the scanner translates the arguments to |
| | | :class:`~pyramid.view.view_config` into a call to the |
| | | :meth:`pyramid.config.Configurator.add_view` method, effectively: |
| | |
| | | |
| | | config.add_view(hello) |
| | | |
| | | Declarative Configuration |
| | | ------------------------- |
| | | Summary |
| | | ------- |
| | | |
| | | A third mode of configuration can be employed when you create a |
| | | :app:`Pyramid` application named *declarative configuration*. This mode uses |
| | | an XML language known as :term:`ZCML` to represent configuration statements |
| | | rather than Python. ZCML is not built-in to Pyramid, but almost everything |
| | | that can be configured imperatively can also be configured via ZCML if you |
| | | install the :term:`pyramid_zcml` package. |
| | | |
| | | There are two ways to configure a :app:`Pyramid` application: declaratively |
| | | and imperatively. You can choose the mode you're most comfortable with; both |
| | | are completely equivalent. Examples in this documentation will use both |
| | | modes interchangeably. |
| | |
| | | single: debug_all |
| | | single: reload_all |
| | | single: debug settings |
| | | single: debug_routematch |
| | | single: prevent_http_cache |
| | | single: reload settings |
| | | single: default_locale_name |
| | | single: environment variables |
| | | single: Mako environment settings |
| | | single: ini file settings |
| | | single: PasteDeploy settings |
| | | |
| | |
| | | flag is meaningful to Chameleon and Mako templates, as well as most |
| | | third-party template rendering extensions. |
| | | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_RELOAD_TEMPLATES`` | ``reload_templates`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------+ |
| | | +---------------------------------+--------------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+================================+ |
| | | | ``PYRAMID_RELOAD_TEMPLATES`` | ``pyramid.reload_templates`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+--------------------------------+ |
| | | |
| | | Reloading Assets |
| | | ---------------- |
| | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_RELOAD_ASSETS`` | ``reload_assets`` | |
| | | | ``PYRAMID_RELOAD_ASSETS`` | ``pyramid.reload_assets`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | |
| | | |
| | | .. note:: For backwards compatibility purposes, aliases can be |
| | | used for configurating asset reloading: ``PYRAMID_RELOAD_RESOURCES`` (envvar) |
| | | and ``reload_resources`` (config file). |
| | | and ``pyramid.reload_resources`` (config file). |
| | | |
| | | Debugging Authorization |
| | | ----------------------- |
| | |
| | | Print view authorization failure and success information to stderr |
| | | when this value is true. See also :ref:`debug_authorization_section`. |
| | | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_DEBUG_AUTHORIZATION`` | ``debug_authorization`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------+ |
| | | +---------------------------------+-----------------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+===================================+ |
| | | | ``PYRAMID_DEBUG_AUTHORIZATION`` | ``pyramid.debug_authorization`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------------+ |
| | | |
| | | Debugging Not Found Errors |
| | | -------------------------- |
| | |
| | | Print view-related ``NotFound`` debug messages to stderr |
| | | when this value is true. See also :ref:`debug_notfound_section`. |
| | | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_DEBUG_NOTFOUND`` | ``debug_notfound`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------+ |
| | | +---------------------------------+------------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+==============================+ |
| | | | ``PYRAMID_DEBUG_NOTFOUND`` | ``pyramid.debug_notfound`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+------------------------------+ |
| | | |
| | | Debugging Route Matching |
| | | ------------------------ |
| | |
| | | Print debugging messages related to :term:`url dispatch` route matching when |
| | | this value is true. See also :ref:`debug_routematch_section`. |
| | | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_DEBUG_ROUTEMATCH`` | ``debug_routematch`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------+ |
| | | +---------------------------------+--------------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+================================+ |
| | | | ``PYRAMID_DEBUG_ROUTEMATCH`` | ``pyramid.debug_routematch`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+--------------------------------+ |
| | | |
| | | .. _preventing_http_caching: |
| | | |
| | | Preventing HTTP Caching |
| | | ------------------------ |
| | | |
| | | Prevent the ``http_cache`` view configuration argument from having any effect |
| | | globally in this process when this value is true. No http caching-related |
| | | response headers will be set by the Pyramid ``http_cache`` view configuration |
| | | feature when this is true. See also :ref:`influencing_http_caching`. |
| | | |
| | | +---------------------------------+----------------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+==================================+ |
| | | | ``PYRAMID_PREVENT_HTTP_CACHE`` | ``pyramid.prevent_http_cache`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+----------------------------------+ |
| | | |
| | | Debugging All |
| | | ------------- |
| | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_DEBUG_ALL`` | ``debug_all`` | |
| | | | ``PYRAMID_DEBUG_ALL`` | ``pyramid.debug_all`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_RELOAD_ALL`` | ``reload_all`` | |
| | | | ``PYRAMID_RELOAD_ALL`` | ``pyramid.reload_all`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | |
| | | :term:`locale negotiator` is not registered. See also |
| | | :ref:`localization_deployment_settings`. |
| | | |
| | | +---------------------------------+-----------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+=============================+ |
| | | | ``PYRAMID_DEFAULT_LOCALE_NAME`` | ``default_locale_name`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------+ |
| | | +---------------------------------+-----------------------------------+ |
| | | | Environment Variable Name | Config File Setting Name | |
| | | +=================================+===================================+ |
| | | | ``PYRAMID_DEFAULT_LOCALE_NAME`` | ``pyramid.default_locale_name`` | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | +---------------------------------+-----------------------------------+ |
| | | |
| | | .. _mako_template_renderer_settings: |
| | | |
| | |
| | | |
| | | [app:main] |
| | | use = egg:MyProject#app |
| | | reload_templates = true |
| | | debug_authorization = true |
| | | 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 |
| | |
| | | application's ``.ini`` file. |
| | | |
| | | If you want to turn all ``debug`` settings (every setting that starts |
| | | with ``debug_``). on in one fell swoop, you can use |
| | | with ``pyramid.debug_``). on in one fell swoop, you can use |
| | | ``PYRAMID_DEBUG_ALL=1`` as an environment variable setting or you may use |
| | | ``debug_all=true`` in the config file. Note that this does not affect |
| | | settings that do not start with ``debug_*`` such as |
| | | ``reload_templates``. |
| | | ``pyramid.debug_all=true`` in the config file. Note that this does not affect |
| | | settings that do not start with ``pyramid.debug_*`` such as |
| | | ``pyramid.reload_templates``. |
| | | |
| | | If you want to turn all ``reload`` settings (every setting that starts |
| | | with ``reload_``) on in one fell swoop, you can use |
| | | If you want to turn all ``pyramid.reload`` settings (every setting that starts |
| | | with ``pyramid.reload_``) on in one fell swoop, you can use |
| | | ``PYRAMID_RELOAD_ALL=1`` as an environment variable setting or you may use |
| | | ``reload_all=true`` in the config file. Note that this does not |
| | | affect settings that do not start with ``reload_*`` such as |
| | | ``debug_notfound``. |
| | | ``pyramid.reload_all=true`` in the config file. Note that this does not |
| | | affect settings that do not start with ``pyramid.reload_*`` such as |
| | | ``pyramid.debug_notfound``. |
| | | |
| | | .. note:: |
| | | Specifying configuration settings via environment variables is generally |
| | |
| | | Understanding the Distinction Between ``reload_templates`` and ``reload_assets`` |
| | | -------------------------------------------------------------------------------- |
| | | |
| | | The difference between ``reload_assets`` and ``reload_templates`` is a bit |
| | | subtle. Templates are themselves also treated by :app:`Pyramid` as asset |
| | | files (along with other static files), so the distinction can be confusing. |
| | | It's helpful to read :ref:`overriding_assets_section` for some context |
| | | about assets in general. |
| | | The difference between ``pyramid.reload_assets`` and |
| | | ``pyramid.reload_templates`` is a bit subtle. Templates are themselves also |
| | | treated by :app:`Pyramid` as asset files (along with other static files), so the |
| | | distinction can be confusing. It's helpful to read |
| | | :ref:`overriding_assets_section` for some context about assets in general. |
| | | |
| | | When ``reload_templates`` is true, :app:`Pyramid` takes advantage of the |
| | | When ``pyramid.reload_templates`` is true, :app:`Pyramid` takes advantage of the |
| | | underlying templating systems' ability to check for file modifications to an |
| | | individual template file. When ``reload_templates`` is true but |
| | | ``reload_assets`` is *not* true, the template filename returned by the |
| | | individual template file. When ``pyramid.reload_templates`` is true but |
| | | ``pyramid.reload_assets`` is *not* true, the template filename returned by the |
| | | ``pkg_resources`` package (used under the hood by asset resolution) is cached |
| | | by :app:`Pyramid` on the first request. Subsequent requests for the same |
| | | template file will return a cached template filename. The underlying |
| | | templating system checks for modifications to this particular file for every |
| | | request. Setting ``reload_templates`` to ``True`` doesn't affect performance |
| | | dramatically (although it should still not be used in production because it |
| | | has some effect). |
| | | request. Setting ``pyramid.reload_templates`` to ``True`` doesn't affect |
| | | performance dramatically (although it should still not be used in production |
| | | because it has some effect). |
| | | |
| | | However, when ``reload_assets`` is true, :app:`Pyramid` will not cache the |
| | | template filename, meaning you can see the effect of changing the content of |
| | | an overridden asset directory for templates without restarting the server |
| | | However, when ``pyramid.reload_assets`` is true, :app:`Pyramid` will not cache |
| | | the template filename, meaning you can see the effect of changing the content |
| | | of an overridden asset directory for templates without restarting the server |
| | | after every change. Subsequent requests for the same template file may |
| | | return different filenames based on the current state of overridden asset |
| | | directories. Setting ``reload_assets`` to ``True`` affects performance |
| | | directories. Setting ``pyramid.reload_assets`` to ``True`` affects performance |
| | | *dramatically*, slowing things down by an order of magnitude for each |
| | | template rendering. However, it's convenient to enable when moving files |
| | | around in overridden asset directories. ``reload_assets`` makes the system |
| | | *very slow* when templates are in use. Never set ``reload_assets`` to |
| | | ``True`` on a production system. |
| | | around in overridden asset directories. ``pyramid.reload_assets`` makes the |
| | | system *very slow* when templates are in use. Never set |
| | | ``pyramid.reload_assets`` to ``True`` on a production system. |
| | | |
| | | .. index:: |
| | | par: settings; adding custom |
| | | |
| | | .. _adding_a_custom_setting: |
| | | |
| | |
| | | .. index:: |
| | | single: hello world program |
| | | |
| | | .. _firstapp_chapter: |
| | | |
| | | Creating Your First :app:`Pyramid` Application |
| | |
| | | Hello World, Goodbye World |
| | | -------------------------- |
| | | |
| | | Here's one of the very simplest :app:`Pyramid` applications, configured |
| | | imperatively: |
| | | Here's one of the very simplest :app:`Pyramid` applications: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | app = config.make_wsgi_app() |
| | | serve(app, host='0.0.0.0') |
| | | |
| | | Let's break this down this piece-by-piece. |
| | | Let's break this down piece-by-piece. |
| | | |
| | | Configurator Construction |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | :class:`~pyramid.config.Configurator` class. The resulting ``config`` object |
| | | represents an API which the script uses to configure this particular |
| | | :app:`Pyramid` application. Methods called on the Configurator will cause |
| | | registrations to be made in a :term:`application registry` associated with |
| | | registrations to be made in an :term:`application registry` associated with |
| | | the application. |
| | | |
| | | .. _adding_configuration: |
| | |
| | | For more information about :term:`view configuration`, see |
| | | :ref:`view_config_chapter`. |
| | | |
| | | An example of using *declarative* configuration (:term:`ZCML`) instead of |
| | | imperative configuration to create a similar "hello world" is available |
| | | within the documentation for :term:`pyramid_zcml`. |
| | |
| | | caused the not found view to be called. The value of |
| | | ``request.exception.message`` will be a value explaining why the not found |
| | | error was raised. This message will be different when the |
| | | ``debug_notfound`` environment setting is true than it is when it is |
| | | false. |
| | | ``pyramid.debug_notfound`` environment setting is true than it is when it |
| | | is false. |
| | | |
| | | .. warning:: When a NotFound view callable accepts an argument list as |
| | | described in :ref:`request_and_context_view_definitions`, the ``context`` |
| | |
| | | ``request.exception.message`` will be a value explaining why the forbidden |
| | | was raised and ``request.exception.result`` will be extended information |
| | | about the forbidden exception. These messages will be different when the |
| | | ``debug_authorization`` environment setting is true than it is when it is |
| | | false. |
| | | ``pyramid.debug_authorization`` environment setting is true than it is when |
| | | it is false. |
| | | |
| | | .. index:: |
| | | single: request factory |
| | |
| | | when adding renderer global values exists in :ref:`adding_renderer_globals`. |
| | | |
| | | .. index:: |
| | | single: renderer globals |
| | | single: adding renderer globals |
| | | |
| | | .. _adding_renderer_globals: |
| | | |
| | |
| | | |
| | | Unlike many other web frameworks, :app:`Pyramid` does not eagerly create a |
| | | global response object. Adding a :term:`response callback` allows an |
| | | application to register an action to be performed against a response object |
| | | once it is created, usually in order to mutate it. |
| | | application to register an action to be performed against whatever response |
| | | object is returned by a view, usually in order to mutate the response. |
| | | |
| | | The :meth:`pyramid.request.Request.add_response_callback` method is used to |
| | | register a response callback. |
| | |
| | | |
| | | .. index:: |
| | | single: IResponse |
| | | single: special view responses |
| | | |
| | | .. _using_iresponse: |
| | | |
| | |
| | | |
| | | It is possible to control how Pyramid treats the result of calling a view |
| | | callable on a per-type basis by using a hook involving |
| | | :meth:`pyramid.config.Configurator.add_response_adapter`. |
| | | :meth:`pyramid.config.Configurator.add_response_adapter` or the |
| | | :class:`~pyramid.response.response_adapter` decorator. |
| | | |
| | | .. note:: This feature is new as of Pyramid 1.1. |
| | | |
| | |
| | | :class:`pyramid.interfaces.IResponse` and you'll have to ensure that it's |
| | | marked up with ``zope.interface.implements(IResponse)``: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.interfaces import IResponse |
| | | from zope.interface import implements |
| | | |
| | |
| | | startup time, as by their nature, instances of this class (and instances of |
| | | subclasses of the class) will natively provide IResponse. The adapter |
| | | registered for ``webob.Response`` simply returns the response object. |
| | | |
| | | Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, |
| | | you can use the :class:`pyramid.response.response_adapter` decorator: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | from pyramid.response import response_adapter |
| | | |
| | | @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) |
| | | |
| | | The :class:`~pyramid.response.response_adapter` decorator will have no effect |
| | | until activated by a :term:`scan`. |
| | | |
| | | .. index:: |
| | | single: view mapper |
| | |
| | | For full details, please read the `Venusian documentation |
| | | <http://docs.repoze.org/venusian>`_. |
| | | |
| | | .. _registering_tweens: |
| | | |
| | | Registering "Tweens" |
| | | -------------------- |
| | | |
| | | .. note:: Tweens are a feature which were added in Pyramid 1.1.1. They are |
| | | not available in any previous version. |
| | | |
| | | A :term:`tween` (a contraction of the word "between") is a bit of code that |
| | | sits between the Pyramid router's main request handling function and the |
| | | upstream WSGI component that uses :app:`Pyramid` as its "app". This is a |
| | | feature that may be used by Pyramid framework extensions, to provide, for |
| | | example, Pyramid-specific view timing support bookkeeping code that examines |
| | | exceptions before they are returned to the upstream WSGI application. Tweens |
| | | behave a bit like :term:`WSGI` middleware but they have the benefit of |
| | | running in a context in which they have access to the Pyramid |
| | | :term:`application registry` as well as the Pyramid rendering machinery. |
| | | |
| | | To make use of tweens, you must construct a "tween factory". A tween factory |
| | | must be a callable (or a :term:`dotted Python name` to such a callable) which |
| | | accepts two arguments: ``handler`` and ``registry``. ``handler`` will be the |
| | | either the main Pyramid request handling function or another tween (if more |
| | | than one tween is configured into the request handling chain). ``registry`` |
| | | will be the Pyramid :term:`application registry` represented by this |
| | | Configurator. A tween factory must return a tween when it is called. |
| | | |
| | | A tween is a callable which accepts a :term:`request` object and returns a |
| | | two-tuple a :term:`response` object. |
| | | |
| | | Once you've created a tween factory, you can register it into the implicit |
| | | tween chain using the :meth:`pyramid.config.Configurator.add_tween` method. |
| | | |
| | | Here's an example creating a tween factory and registering it: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | import time |
| | | from pyramid.settings import asbool |
| | | import logging |
| | | |
| | | log = logging.getLogger(__name__) |
| | | |
| | | def timing_tween_factory(handler, registry): |
| | | if asbool(registry.settings.get('do_timing')): |
| | | # if timing support is enabled, return a wrapper |
| | | def timing_tween(request): |
| | | start = time.time() |
| | | try: |
| | | response = handler(request) |
| | | finally: |
| | | end = time.time() |
| | | log.debug('The request took %s seconds' % |
| | | (end - start)) |
| | | return response |
| | | return timing_tween |
| | | # if timing support is not enabled, return the original |
| | | # handler |
| | | return handler |
| | | |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | config.add_tween(timing_tween_factory) |
| | | |
| | | The ``request`` argument to a tween will be the request created by Pyramid's |
| | | router when it receives a WSGI request. |
| | | |
| | | If more than one call to :meth:`pyramid.config.Configurator.add_tween` is |
| | | made within a single application configuration, the tweens will be chained |
| | | together at application startup time. The *first* tween factory added via |
| | | ``add_tween`` will be called with the Pyramid exception view tween factory as |
| | | its ``handler`` argument, then the tween factory added directly after that |
| | | one will be called with the result of the first tween factory as its |
| | | ``handler`` argument, and so on, ad infinitum until all tween factories have |
| | | been called. The Pyramid router will use the outermost tween produced by this |
| | | chain (the tween generated by the very last tween factory added) as its |
| | | request handler function. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.config import Configurator |
| | | |
| | | config = Configurator() |
| | | 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:: |
| | | |
| | | INGRESS (implicit) |
| | | myapp.tween_factory2 |
| | | myapp.tween_factory1 |
| | | pyramid.tweens.excview_tween_factory (implicit) |
| | | MAIN (implicit) |
| | | |
| | | By default, as described above, the ordering of the chain is controlled |
| | | entirely by the relative ordering of calls to |
| | | :meth:`pyramid.config.Configurator.add_tween`. However, the caller of |
| | | add_tween can provide an optional hint that can influence the implicit tween |
| | | chain ordering by supplying ``under`` or ``over`` (or both) arguments to |
| | | :meth:`~pyramid.config.Configurator.add_tween`. These hints are only used |
| | | used when an explicit tween chain is not used (when the ``pyramid.tweens`` |
| | | configuration value is not set). |
| | | |
| | | Allowable values for ``under`` or ``over`` (or both) are: |
| | | |
| | | - ``None`` (the default). |
| | | |
| | | - A :term:`dotted Python name` to a tween factory: a string representing the |
| | | predicted dotted name of a tween factory added in a call to ``add_tween`` |
| | | in the same configuration session. |
| | | |
| | | - A "tween alias": a string representing the predicted value of ``alias`` in |
| | | a separate call to ``add_tween`` in the same configuration session |
| | | |
| | | - One of the constants :attr:`pyramid.tweens.MAIN`, |
| | | :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. |
| | | |
| | | Effectively, ``under`` means "closer to the main Pyramid application than", |
| | | ``over`` means "closer to the request ingress than". |
| | | |
| | | For example, the following call to |
| | | :meth:`~pyramid.config.Configurator.add_tween` will attempt to place the |
| | | tween factory represented by ``myapp.tween_factory`` directly 'above' (in |
| | | ``paster ptweens`` order) the main Pyramid request handler. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | import pyramid.tweens |
| | | |
| | | config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN) |
| | | |
| | | The above example will generate an implicit tween chain that looks like |
| | | this:: |
| | | |
| | | INGRESS (implicit) |
| | | pyramid.tweens.excview_tween_factory (implicit) |
| | | myapp.tween_factory |
| | | MAIN (implicit) |
| | | |
| | | Likewise, calling the following call to |
| | | :meth:`~pyramid.config.Configurator.add_tween` will attempt to place this |
| | | tween factory 'above' the main handler but 'below' a separately added tween |
| | | factory: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | 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') |
| | | |
| | | The above example will generate an implicit tween chain that looks like |
| | | this:: |
| | | |
| | | INGRESS (implicit) |
| | | pyramid.tweens.excview_tween_factory (implicit) |
| | | myapp.tween_factory1 |
| | | myapp.tween_factory2 |
| | | MAIN (implicit) |
| | | |
| | | Specifying neither ``over`` nor ``under`` is equivalent to specifying |
| | | ``under=INGRESS``. |
| | | |
| | | If an ``under`` or ``over`` value is provided that does not match a tween |
| | | factory dotted name or alias in the current configuration, that value will be |
| | | ignored. It is not an error to provide an ``under`` or ``over`` value that |
| | | matches an unused tween factory. |
| | | |
| | | :meth:`~pyramid.config.Configurator.add_tween` also accepts an ``alias`` |
| | | argument. If ``alias`` is not ``None``, should be a string. The string will |
| | | represent a value that other callers of ``add_tween`` may pass as an |
| | | ``under`` and ``over`` argument instead of a dotted name to a tween factory. |
| | | For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | import pyramid.tweens |
| | | |
| | | config.add_tween('myapp.tween_factory1', |
| | | alias='one' |
| | | over=pyramid.tweens.MAIN) |
| | | config.add_tween('myapp.tween_factory2', |
| | | alias='two' |
| | | over=pyramid.tweens.MAIN, |
| | | under='one') |
| | | |
| | | Alias names are only useful in relation to ``under`` and ``over`` values. |
| | | They cannot be used in explicit tween chain configuration, or anywhere else. |
| | | |
| | | Implicit tween ordering is obviously only best-effort. Pyramid will attempt |
| | | to provide an implicit order of tweens as best it can using hints provided by |
| | | calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's |
| | | only best-effort, if very precise tween ordering is required, the only |
| | | surefire way to get it is to use an explicit tween order. The deploying user |
| | | can override the implicit tween inclusion and ordering implied by calls to |
| | | :meth:`~pyramid.config.Configurator.add_tween` entirely by using the |
| | | ``pyramid.tweens`` settings value. When used, this settings value must be a |
| | | list of Python dotted names which will override the ordering (and inclusion) |
| | | of tween factories in the implicit tween chain. For example: |
| | | |
| | | .. code-block:: ini |
| | | :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 |
| | | |
| | | In the above configuration, calls made during configuration to |
| | | :meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is |
| | | telling the system to use the tween factories he has listed in the |
| | | ``pyramid.tweens`` configuration setting (each is a :term:`dotted Python |
| | | name` which points to a tween factory) instead of any tween factories added |
| | | via :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory |
| | | in the ``pyramid.tweens`` list will be used as the producer of the effective |
| | | :app:`Pyramid` request handling function; it will wrap the tween factory |
| | | declared directly "below" it, ad infinitum. The "main" Pyramid request |
| | | handler is implicit, and always "at the bottom". |
| | | |
| | | .. note:: Pyramid's own :term:`exception view` handling logic is implemented |
| | | as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`. |
| | | If Pyramid exception view handling is desired, and tween factories are |
| | | specified via the ``pyramid.tweens`` configuration setting, the |
| | | :func:`pyramid.tweens.excview_tween_factory` function must be added to the |
| | | ``pyramid.tweens`` configuration setting list explicitly. If it is not |
| | | present, Pyramid will not perform exception view handling. |
| | | |
| | | Pyramid will prevent the same tween factory from being added to the tween |
| | | chain more than once using configuration conflict detection. If you wish to |
| | | add the same tween factory more than once in a configuration, you should |
| | | either: a) use a tween factory that is an instance rather than a function or |
| | | class, b) use a function or class as a tween factory with the same logic as |
| | | the other tween factory it conflicts with but with a different ``__name__`` |
| | | attribute or c) call :meth:`pyramid.config.Configurator.commit` between calls |
| | | to :meth:`pyramid.config.Configurator.add_tween`. |
| | | |
| | | If a cycle is detected in implicit tween ordering when ``over`` and ``under`` |
| | | are used in any call to "add_tween", an exception will be raised at startup |
| | | time. |
| | | |
| | | The ``paster ptweens`` command-line utility can be used to report the current |
| | | implict and explicit tween chains used by an application. See |
| | | :ref:`displaying_tweens`. |
| | |
| | | calls to :meth:`pyramid.config.Configurator.add_route` in its startup |
| | | code. |
| | | |
| | | .. index:: |
| | | single: hybrid applications |
| | | |
| | | Hybrid Applications |
| | | ------------------- |
| | | |
| | |
| | | :ref:`route_factories`. Both the global root factory and default |
| | | root factory were explained previously within |
| | | :ref:`the_resource_tree`. |
| | | |
| | | .. index:: |
| | | pair: hybrid applications; *traverse route pattern |
| | | |
| | | .. _using_traverse_in_a_route_pattern: |
| | | |
| | |
| | | the global root, or the object returned by the ``factory`` associated |
| | | with this route). |
| | | |
| | | .. index:: |
| | | pair: hybrid applications; global views |
| | | |
| | | Making Global Views Match |
| | | +++++++++++++++++++++++++ |
| | | |
| | |
| | | config.add_view('myproject.views.bazbuz', name='bazbuz') |
| | | |
| | | .. index:: |
| | | pair: hybrid applications; *subpath |
| | | single: route subpath |
| | | single: subpath (route) |
| | | |
| | |
| | | There are certain extremely rare cases when you'd like to influence the |
| | | traversal :term:`subpath` when a route matches without actually performing |
| | | traversal. For instance, the :func:`pyramid.wsgi.wsgiapp2` decorator and the |
| | | :class:`pyramid.view.static` helper attempt to compute ``PATH_INFO`` from the |
| | | request's subpath, so it's useful to be able to influence this value. |
| | | :class:`pyramid.static.static_view` helper attempt to compute ``PATH_INFO`` |
| | | from the request's subpath when its ``use_subpath`` argument is ``True``, so |
| | | it's useful to be able to influence this value. |
| | | |
| | | When ``*subpath`` exists in a pattern, no path is actually traversed, |
| | | but the traversal algorithm will return a :term:`subpath` list implied |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | config.add_route('static', '/static/*subpath') |
| | | config.add_view('mypackage.views.static_view', route_name='static') |
| | | from pryamid.static import static_view |
| | | |
| | | Where ``mypackage.views.static_view`` is an instance of |
| | | :class:`pyramid.view.static`. This effectively tells the static helper to |
| | | traverse everything in the subpath as a filename. |
| | | www = static_view('mypackage:static', use_subpath=True) |
| | | |
| | | config.add_route('static', '/static/*subpath') |
| | | config.add_view(www, route_name='static') |
| | | |
| | | ``mypackage.views.www`` is an instance of |
| | | :class:`pyramid.static.static_view`. This effectively tells the static |
| | | helper to traverse everything in the subpath as a filename. |
| | | |
| | | .. index:: |
| | | pair: hybrid applications; corner cases |
| | | |
| | | Corner Cases |
| | | ------------ |
| | |
| | | |
| | | ``myapplication/locale/myapplication.pot``. |
| | | |
| | | .. index:: |
| | | single: translation domains |
| | | |
| | | Translation Domains |
| | | +++++++++++++++++++ |
| | | |
| | |
| | | .. index:: |
| | | single: localizer |
| | | single: get_localizer |
| | | single: translation |
| | | single: pluralization |
| | | |
| | | Using a Localizer |
| | | ----------------- |
| | |
| | | This returns the locale name negotiated by the currently active |
| | | :term:`locale negotiator` or the :term:`default locale name` if the |
| | | locale negotiator returns ``None``. You can change the default locale |
| | | name by changing the ``default_locale_name`` setting; see |
| | | name by changing the ``pyramid.default_locale_name`` setting; see |
| | | :ref:`default_locale_name_setting`. |
| | | |
| | | Once :func:`~pyramid.i18n.get_locale_name` is first run, the locale |
| | |
| | | equivalent. For those, you can always use the more manual translation |
| | | facility described in :ref:`performing_a_translation`. |
| | | |
| | | .. index:: |
| | | single: Mako i18n |
| | | |
| | | Mako Pyramid I18N Support |
| | | ------------------------- |
| | | |
| | |
| | | Localization-Related Deployment Settings |
| | | ---------------------------------------- |
| | | |
| | | A :app:`Pyramid` application will have a ``default_locale_name`` |
| | | A :app:`Pyramid` application will have a ``pyramid.default_locale_name`` |
| | | setting. This value represents the :term:`default locale name` used |
| | | when the :term:`locale negotiator` returns ``None``. Pass it to the |
| | | :mod:`~pyramid.config.Configurator` constructor at startup |
| | |
| | | :linenos: |
| | | |
| | | from pyramid.config import Configurator |
| | | config = Configurator(settings={'default_locale_name':'de'}) |
| | | config = Configurator(settings={'pyramid.default_locale_name':'de'}) |
| | | |
| | | You may alternately supply a ``default_locale_name`` via an |
| | | You may alternately supply a ``pyramid.default_locale_name`` via an |
| | | application's Paster ``.ini`` file: |
| | | |
| | | .. code-block:: ini |
| | |
| | | |
| | | [app:main] |
| | | use = egg:MyProject#app |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | default_locale_name = de |
| | | 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 Paste config file, it will default to ``en``. |
| | |
| | | |
| | | from pyramid.threadlocal import get_current_registry |
| | | settings = get_current_registry().settings |
| | | default_locale_name = settings['default_locale_name'] |
| | | default_locale_name = settings['pyramid.default_locale_name'] |
| | | |
| | | .. index:: |
| | | single: detecting langauges |
| | | |
| | | "Detecting" Available Languages |
| | | ------------------------------- |
| | |
| | | pair: locale; negotiator |
| | | single: translation directory |
| | | |
| | | .. index:: |
| | | pair: activating; translation |
| | | |
| | | .. _activating_translation: |
| | | |
| | | Activating Translation |
| | |
| | | - add at least one :term:`translation directory` to your application. |
| | | |
| | | - ensure that your application sets the :term:`locale name` correctly. |
| | | |
| | | .. index:: |
| | | pair: translation directory; adding |
| | | |
| | | .. _adding_a_translation_directory: |
| | | |
| | |
| | | if both translation directories contain translations for the same |
| | | locale and :term:`translation domain`. |
| | | |
| | | .. index:: |
| | | pair: setting; locale |
| | | |
| | | Setting the Locale |
| | | ~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | function into that application as required. See |
| | | :ref:`custom_locale_negotiator`. |
| | | |
| | | .. index:: |
| | | single: locale negotiator |
| | | |
| | | .. _locale_negotiators: |
| | | |
| | | Locale Negotiators |
| | |
| | | Before You Install |
| | | ------------------ |
| | | |
| | | You will need `Python <http://python.org>`_ version 2.4 or better to |
| | | You will need `Python <http://python.org>`_ version 2.5 or better to |
| | | run :app:`Pyramid`. |
| | | |
| | | .. sidebar:: Python Versions |
| | | |
| | | As of this writing, :app:`Pyramid` has been tested under Python |
| | | 2.4.6, Python 2.5.4 and Python 2.6.2, and Python 2.7. To ensure |
| | | backwards compatibility, development of :app:`Pyramid` is |
| | | currently done primarily under Python 2.4 and Python 2.5. |
| | | :app:`Pyramid` does not run under any version of Python before |
| | | 2.4, and does not yet run under Python 3.X. |
| | | As of this writing, :app:`Pyramid` has been tested under Python 2.5.5, |
| | | Python 2.6.6, and Python 2.7.2. :app:`Pyramid` does not run under any |
| | | version of Python before 2.5, and does not yet run under Python 3.X. |
| | | |
| | | :app:`Pyramid` is known to run on all popular Unix-like systems such as |
| | | Linux, MacOS X, and FreeBSD as well as on Windows platforms. It is also |
| | | known to run on Google's App Engine and :term:`Jython`. |
| | | known to run on Google's App Engine, :term:`PyPy` (1.5), and :term:`Jython` |
| | | (2.5.2). |
| | | |
| | | :app:`Pyramid` installation does not require the compilation of any |
| | | C code, so you need only a Python interpreter that meets the |
| | |
| | | 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 development tools. |
| | | |
| | | .. index:: |
| | | pair: install; Python (from package, UNIX) |
| | | |
| | | Package Manager Method |
| | | ++++++++++++++++++++++ |
| | |
| | | |
| | | Once these steps are performed, the Python interpreter will usually be |
| | | invokable via ``python2.6`` from a shell prompt. |
| | | |
| | | .. index:: |
| | | pair: install; Python (from source, UNIX) |
| | | |
| | | Source Compile Method |
| | | +++++++++++++++++++++ |
| | |
| | | On Mac OS X, installing `XCode |
| | | <http://developer.apple.com/tools/xcode/>`_ has much the same effect. |
| | | |
| | | Once you've got development tools installed on your system, On the |
| | | same system, to install a Python 2.6 interpreter from *source*, use |
| | | the following commands: |
| | | Once you've got development tools installed on your system, you can |
| | | install a Python 2.6 interpreter from *source*, on the same system, |
| | | using the following commands: |
| | | |
| | | .. code-block:: text |
| | | |
| | |
| | | Once these steps are performed, the Python interpreter will be |
| | | invokable via ``$HOME/opt/Python-2.6.4/bin/python`` from a shell |
| | | prompt. |
| | | |
| | | .. index:: |
| | | pair: install; Python (from package, Windows) |
| | | |
| | | If You Don't Yet Have A Python Interpreter (Windows) |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | .. code-block:: text |
| | | |
| | | [chrism@vitaminf pyramid]$ python |
| | | Python 2.4.5 (#1, Aug 29 2008, 12:27:37) |
| | | [GCC 4.0.1 (Apple Inc. build 5465)] on darwin |
| | | Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32) |
| | | [GCC 4.4.3] on linux2 |
| | | Type "help", "copyright", "credits" or "license" for more information. |
| | | >>> import setuptools |
| | | |
| | | If running ``import setuptools`` does not raise an ``ImportError``, it |
| | | means that setuptools is already installed into your Python |
| | | interpreter. If ``import setuptools`` fails, you will need to install |
| | | setuptools manually. Note that above we're using a Python 2.4-series |
| | | setuptools manually. Note that above we're using a Python 2.6-series |
| | | interpreter on Mac OS X; your output may differ if you're using a |
| | | later Python version or a different platform. |
| | | |
| | |
| | | $ sudo python ez_setup.py |
| | | |
| | | .. index:: |
| | | single: virtualenv |
| | | pair: install; virtualenv |
| | | |
| | | Installing the ``virtualenv`` Package |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | |
| | | .. index:: |
| | | single: virtualenv |
| | | pair: Python; virtual environment |
| | | |
| | | Creating the Virtual Python Environment |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | :ref:`appengine_tutorial` documents the steps required to install a |
| | | :app:`Pyramid` application on Google App Engine. |
| | | |
| | | .. index:: |
| | | single: installing on Jython |
| | | |
| | | Installing :app:`Pyramid` on Jython |
| | | -------------------------------------- |
| | | |
| | |
| | | ============================== |
| | | |
| | | :app:`Pyramid` is a general, open source, Python web application development |
| | | *framework*. Its primary goal is to make it easier for a developer to create |
| | | web applications. The type of application being created could be a |
| | | spreadsheet, a corporate intranet, or a social networking platform; Pyramid's |
| | | generality enables it to be used to build an unconstrained variety of web |
| | | applications. |
| | | *framework*. Its primary goal is to make it easier for a Python developer to |
| | | create web applications. |
| | | |
| | | .. sidebar:: Frameworks vs. Libraries |
| | | |
| | |
| | | own via a set of libraries if the framework provides a set of |
| | | facilities that fits your application requirements. |
| | | |
| | | The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made |
| | | in July of 2008. We have worked hard to ensure that Pyramid continues to |
| | | follow the design and engineering principles that we consider to be the core |
| | | characteristics of a successful framework: |
| | | Pyramid attempts to follow these design and engineering principles: |
| | | |
| | | Simplicity |
| | | :app:`Pyramid` takes a *"pay only for what you eat"* approach. This means |
| | | that you can get results even if you have only a partial understanding of |
| | | :app:`Pyramid`. It doesn’t force you to use any particular technology to |
| | | produce an application, and we try to keep the core set of concepts that |
| | | you need to understand to a minimum. |
| | | :app:`Pyramid` takes a *"pay only for what you eat"* approach. You can get |
| | | results even if you have only a partial understanding of :app:`Pyramid`. |
| | | It doesn’t force you to use any particular technology to produce an |
| | | application, and we try to keep the core set of concepts that you need to |
| | | understand to a minimum. |
| | | |
| | | Minimalism |
| | | :app:`Pyramid` concentrates on providing fast, high-quality solutions to |
| | | the fundamental problems of creating a web application: the mapping of URLs |
| | | to code, templating, security and serving static assets. We consider these |
| | | to be the core activities that are common to nearly all web applications. |
| | | :app:`Pyramid` tries to solve only the the fundamental problems of creating |
| | | a web application: the mapping of URLs to code, templating, security and |
| | | serving static assets. We consider these to be the core activities that are |
| | | common to nearly all web applications. |
| | | |
| | | Documentation |
| | | Pyramid's minimalism means that it is relatively easy for us to maintain |
| | | extensive and up-to-date documentation. It is our goal that no aspect of |
| | | Pyramid remains undocumented. |
| | | Pyramid's minimalism means that it is easier for us to maintain complete |
| | | and up-to-date documentation. It is our goal that no aspect of Pyramid |
| | | is undocumented. |
| | | |
| | | Speed |
| | | :app:`Pyramid` is designed to provide noticeably fast execution for common |
| | | tasks such as templating and simple response generation. Although the |
| | | “hardware is cheap” mantra may appear to offer a ready solution to speed |
| | | problems, the limits of this approach become painfully evident when one |
| | | tasks such as templating and simple response generation. Although “hardware |
| | | is cheap", the limits of this approach become painfully evident when one |
| | | finds him or herself responsible for managing a great many machines. |
| | | |
| | | Reliability |
| | |
| | | open source license <http://repoze.org/license.html>`_. |
| | | |
| | | .. index:: |
| | | single: Pylons |
| | | single: Agendaless Consulting |
| | | single: repoze namespace package |
| | | single: Pylons Project |
| | | |
| | | What Is The Pylons Project? |
| | | --------------------------- |
| | | |
| | | :app:`Pyramid` is a member of the collection of software published under the |
| | | Pylons Project. Pylons software is written by a loose-knit community of |
| | | contributors. The `Pylons Project website <http://docs.pylonsproject.org>`_ |
| | | contributors. The `Pylons Project website <http://pylonsproject.org>`_ |
| | | includes details about how :app:`Pyramid` relates to the Pylons Project. |
| | | |
| | | .. index:: |
| | |
| | | :app:`Pyramid` and Other Web Frameworks |
| | | ------------------------------------------ |
| | | |
| | | Until the end of 2010, :app:`Pyramid` was known as :mod:`repoze.bfg`; it was |
| | | merged into the Pylons project as :app:`Pyramid` in November of that year. |
| | | The first release of Pyramid's predecessor (named :mod:`repoze.bfg`) was made |
| | | in July of 2008. At the end of 2010, we changed the name of |
| | | :mod:`repoze.bfg` to :app:`Pyramid`. It was merged into the Pylons project |
| | | as :app:`Pyramid` in November of that year. |
| | | |
| | | :app:`Pyramid` was inspired by :term:`Zope`, :term:`Pylons` (version |
| | | 1.0) and :term:`Django`. As a result, :app:`Pyramid` borrows several |
| | | concepts and features from each, combining them into a unique web |
| | | framework. |
| | | |
| | | Many features of :app:`Pyramid` trace their origins back to |
| | | :term:`Zope`. Like Zope applications, :app:`Pyramid` applications |
| | | can be configured via a set of declarative configuration files. Like |
| | | Zope applications, :app:`Pyramid` applications can be easily |
| | | extended: if you obey certain constraints, the application you produce |
| | | can be reused, modified, re-integrated, or extended by third-party |
| | | developers without forking the original application. The concepts of |
| | | :term:`traversal` and declarative security in :app:`Pyramid` were |
| | | pioneered first in Zope. |
| | | Many features of :app:`Pyramid` trace their origins back to :term:`Zope`. |
| | | Like Zope applications, :app:`Pyramid` applications can be easily extended: |
| | | if you obey certain constraints, the application you produce can be reused, |
| | | modified, re-integrated, or extended by third-party developers without |
| | | forking the original application. The concepts of :term:`traversal` and |
| | | declarative security in :app:`Pyramid` were pioneered first in Zope. |
| | | |
| | | The :app:`Pyramid` concept of :term:`URL dispatch` is inspired by the |
| | | :term:`Routes` system used by :term:`Pylons` version 1.0. Like Pylons |
| | |
| | | by Django. :app:`Pyramid` has a documentation culture more like Django's |
| | | than like Zope's. |
| | | |
| | | Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a |
| | | :app:`Pyramid` application developer may use completely imperative |
| | | code to perform common framework configuration tasks such as adding a |
| | | view or a route. In Zope, :term:`ZCML` is typically required for |
| | | similar purposes. In :term:`Grok`, a Zope-based web framework, |
| | | :term:`decorator` objects and class-level declarations are used for |
| | | this purpose. :app:`Pyramid` supports :term:`ZCML` and |
| | | decorator-based configuration, but does not require either. See |
| | | :ref:`configuration_narr` for more information. |
| | | Like :term:`Pylons` version 1.0, but unlike :term:`Zope`, a :app:`Pyramid` |
| | | application developer may use completely imperative code to perform common |
| | | framework configuration tasks such as adding a view or a route. In Zope, |
| | | :term:`ZCML` is typically required for similar purposes. In :term:`Grok`, a |
| | | Zope-based web framework, :term:`decorator` objects and class-level |
| | | declarations are used for this purpose. :app:`Pyramid` supports :term:`ZCML` |
| | | and decorator-based :term:`declarative configuration`, but does not require |
| | | either. See :ref:`configuration_narr` for more information. |
| | | |
| | | Also unlike :term:`Zope` and unlike other "full-stack" frameworks such |
| | | as :term:`Django`, :app:`Pyramid` makes no assumptions about which |
| | |
| | | is actually a straightforward metaphor easily comprehended by anyone who's |
| | | ever used a run-of-the-mill file system with folders and files. |
| | | |
| | | .. index:: |
| | | single: URL dispatch |
| | | |
| | | URL Dispatch |
| | | ------------ |
| | | |
| | |
| | | configuration specified which files would trigger some dynamic code, with the |
| | | default case being to just serve the static file. |
| | | |
| | | .. index:: |
| | | single: traversal |
| | | |
| | | Traversal (aka Resource Location) |
| | | --------------------------------- |
| | | |
| | | .. index:: |
| | | single: traversal overview |
| | | |
| | | Believe it or not, if you understand how serving files from a file system |
| | | works, you understand traversal. And if you understand that a server might do |
| | |
| | | generated anywhere along the way, :app:`Pyramid` will return 404. (This |
| | | isn't precisely true, as you'll see when we learn about view lookup below, |
| | | but the basic idea holds.) |
| | | |
| | | .. index:: |
| | | single: resource |
| | | |
| | | What Is a "Resource"? |
| | | --------------------- |
| | |
| | | .. note:: See the chapter entitled :ref:`resources_chapter` for a more |
| | | technical overview of resources. |
| | | |
| | | .. index:: |
| | | single: view lookup |
| | | |
| | | View Lookup |
| | | ----------- |
| | | |
| | |
| | | You'll use a scaffold to create a project, and you'll create your application |
| | | logic within a package that lives inside the project. Even if your |
| | | application is extremely simple, it is useful to place code that drives the |
| | | application within a package, because a package is more easily extended with |
| | | new code. An application that lives inside a package can also be distributed |
| | | more easily than one which does not live within a package. |
| | | application within a package, because: 1) a package is more easily extended |
| | | with new code and 2) an application that lives inside a package can also be |
| | | distributed more easily than one which does not live within a package. |
| | | |
| | | :app:`Pyramid` comes with a variety of scaffolds that you can use to generate |
| | | a project. Each scaffold makes different configuration assumptions about |
| | |
| | | |
| | | $ bin/paster create -t pyramid_starter |
| | | |
| | | The above command uses the ``paster`` command to create a project using the |
| | | ``pyramid_starter`` scaffold. The ``paster create`` command creates project |
| | | from a scaffold. To use a different scaffold, such as |
| | | The above command uses the ``paster create`` command to create a project with |
| | | the ``pyramid_starter`` scaffold. To use a different scaffold, such as |
| | | ``pyramid_routesalchemy``, you'd just change the last argument. For example: |
| | | |
| | | .. code-block:: text |
| | | |
| | | $ bin/paster create -t pyramid_routesalchemy |
| | | |
| | | ``paster create`` will ask you a single question: the *name* of the |
| | | project. You should use a string without spaces and with only letters |
| | | in it. Here's sample output from a run of ``paster create`` for a |
| | | project we name ``MyProject``: |
| | | ``paster create`` will ask you a single question: the *name* of the project. |
| | | You should use a string without spaces and with only letters in it. Here's |
| | | sample output from a run of ``paster create`` for a project we name |
| | | ``MyProject``: |
| | | |
| | | .. code-block:: text |
| | | |
| | |
| | | The file named ``setup.py`` will be in the root of the paster-generated |
| | | project directory. The ``python`` you're invoking should be the one that |
| | | lives in the ``bin`` directory of your virtual Python environment. Your |
| | | terminal's current working directory *must* the the newly created project |
| | | terminal's current working directory *must* be the newly created project |
| | | directory. For example: |
| | | |
| | | .. code-block:: text |
| | |
| | | |
| | | This will install a :term:`distribution` representing your project into the |
| | | interpreter's library set so it can be found by ``import`` statements and by |
| | | :term:`PasteDeploy` commands such as ``paster serve`` and ``paster pshell``. |
| | | :term:`PasteDeploy` commands such as ``paster serve``, ``paster pshell``, |
| | | ``paster proutes`` and ``paster pviews``. |
| | | |
| | | .. index:: |
| | | single: running tests |
| | |
| | | ``pyramid_starter`` scaffold, a single sample test exists. |
| | | |
| | | .. index:: |
| | | single: interactive shell |
| | | single: IPython |
| | | single: paster pshell |
| | | |
| | | .. _interactive_shell: |
| | | |
| | | The Interactive Shell |
| | | --------------------- |
| | | |
| | | Once you've installed your program for development using ``setup.py |
| | | develop``, you can use an interactive Python shell to examine your |
| | | :app:`Pyramid` project's :term:`resource` and :term:`view` objects from a |
| | | Python prompt. To do so, use your virtualenv's ``paster pshell`` command. |
| | | |
| | | The first argument to ``pshell`` is the path to your application's ``.ini`` |
| | | file. The second is the ``app`` section name inside the ``.ini`` file which |
| | | points to *your application* as opposed to any other section within the |
| | | ``.ini`` file. For example, if your application ``.ini`` file might have a |
| | | ``[app:MyProject]`` section that looks like so: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [app:MyProject] |
| | | use = egg:MyProject |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | If so, you can use the following command to invoke a debug shell using the |
| | | name ``MyProject`` as a section name: |
| | | |
| | | .. code-block:: text |
| | | |
| | | [chrism@vitaminf shellenv]$ ../bin/paster pshell development.ini MyProject |
| | | Python 2.4.5 (#1, Aug 29 2008, 12:27:37) |
| | | [GCC 4.0.1 (Apple Inc. build 5465)] on darwin |
| | | Type "help" for more information. "root" is the Pyramid app root object, |
| | | "registry" is the Pyramid registry object. |
| | | >>> root |
| | | <myproject.resources.MyResource object at 0x445270> |
| | | >>> registry |
| | | <Registry myproject> |
| | | >>> registry.settings['debug_notfound'] |
| | | False |
| | | >>> from myproject.views import my_view |
| | | >>> from pyramid.request import Request |
| | | >>> r = Request.blank('/') |
| | | >>> my_view(r) |
| | | {'project': 'myproject'} |
| | | |
| | | Two names are made available to the pshell user as globals: ``root`` and |
| | | ``registry``. ``root`` is the the object returned by the default :term:`root |
| | | factory` in your application. ``registry`` is the :term:`application |
| | | registry` object associated with your project's application (often accessed |
| | | within view code as ``request.registry``). |
| | | |
| | | If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ installed in |
| | | the interpreter you use to invoke the ``paster`` command, the ``pshell`` |
| | | command will use an IPython interactive shell instead of a standard Python |
| | | interpreter shell. If you don't want this to happen, even if you have |
| | | IPython installed, you can pass the ``--disable-ipython`` flag to the |
| | | ``pshell`` command to use a standard Python interpreter shell |
| | | unconditionally. |
| | | |
| | | .. code-block:: text |
| | | |
| | | [chrism@vitaminf shellenv]$ ../bin/paster pshell --disable-ipython \ |
| | | development.ini MyProject |
| | | |
| | | You should always use a section name argument that refers to the actual |
| | | ``app`` section within the Paste configuration file that points at your |
| | | :app:`Pyramid` application *without any middleware wrapping*. In particular, |
| | | a section name is inappropriate as the second argument to ``pshell`` if the |
| | | configuration section it names is a ``pipeline`` rather than an ``app``. For |
| | | example, if you have the following ``.ini`` file content: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [app:MyProject] |
| | | use = egg:MyProject |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | MyProject |
| | | |
| | | Use ``MyProject`` instead of ``main`` as the section name argument to |
| | | ``pshell`` against the above ``.ini`` file (e.g. ``paster pshell |
| | | development.ini MyProject``). If you use ``main`` instead, an error will |
| | | occur. Use the most specific reference to your application within the |
| | | ``.ini`` file possible as the section name argument. |
| | | |
| | | Press ``Ctrl-D`` to exit the interactive shell (or ``Ctrl-Z`` on Windows). |
| | | |
| | | .. index:: |
| | | single: running an application |
| | | single: paster serve |
| | | single: reload |
| | | single: startup |
| | | single: mod_wsgi |
| | | |
| | | Running The Project Application |
| | | ------------------------------- |
| | |
| | | configuration file settings that influence startup and runtime behavior, see |
| | | :ref:`environment_chapter`. |
| | | |
| | | .. index:: |
| | | single: mod_wsgi |
| | | single: WSGI |
| | | |
| | | Viewing the Application |
| | | ----------------------- |
| | | |
| | |
| | | |
| | | This is the page shown by default when you visit an unmodified ``paster |
| | | create`` -generated ``pyramid_starter`` application in a browser. |
| | | |
| | | If you click on the image shown at the right hand top of the page ("^DT"), |
| | | you'll be presented with a debug toolbar that provides various niceties while |
| | | you're developing. This image will float above every HTML page served by |
| | | :app:`Pyramid` while you develop an application, and allows you show the |
| | | toolbar as necessary. Click on ``Hide`` to hide the toolbar and show the |
| | | image again. |
| | | |
| | | .. image:: project-debug.png |
| | | |
| | | For more information about what the debug toolbar allows you to do, see `the |
| | | documentation for pyramid_debugtoolbar |
| | | <http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/dev/>`_. |
| | | |
| | | The debug toolbar will not be shown (and all debugging will be turned off) |
| | | when you use the ``production.ini`` file instead of the ``development.ini`` |
| | | ini file to run the application. |
| | | |
| | | You can also turn the debug toolbar off by editing ``development.ini`` and |
| | | commenting out the line ``pyramid.include = pyramid_debugtoolbar``. For |
| | | example, instead of: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [app:MyApp] |
| | | ... |
| | | pyramid.include = pyramid_debugtoolbar |
| | | |
| | | Put a hash mark in front of the ``pyramid.include`` line: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [app:MyApp] |
| | | ... |
| | | #pyramid.include = pyramid_debugtoolbar |
| | | |
| | | Then restart the application to see that the toolbar has been turned off. |
| | | |
| | | .. sidebar:: Using an Alternate WSGI Server |
| | | |
| | |
| | | |
| | | The generated ``development.ini`` file looks like so: |
| | | |
| | | .. latexbroken? |
| | | |
| | | .. literalinclude:: MyProject/development.ini |
| | | :language: ini |
| | | :linenos: |
| | | |
| | | This file contains several "sections" including ``[app:MyProject]``, |
| | | ``[pipeline:main]``, and ``[server:main]``. |
| | | ``[pipeline:main]``, ``[server:main]`` and several other sections related to |
| | | logging configuration. |
| | | |
| | | The ``[app:MyProject]`` section represents configuration for your |
| | | application. This section name represents the ``MyProject`` application (and |
| | |
| | | point can thus be referred to as a "Paste application factory in the |
| | | ``MyProject`` project which has the entry point named ``main`` where the |
| | | entry point refers to a ``main`` function in the ``mypackage`` module". |
| | | If indeed if you open up the ``__init__.py`` module generated within the |
| | | Indeed, if you open up the ``__init__.py`` module generated within the |
| | | ``myproject`` package, you'll see a ``main`` function. This is the |
| | | function called by :term:`PasteDeploy` when the ``paster serve`` command |
| | | is invoked against our application. It accepts a global configuration |
| | |
| | | The ``use`` setting is the only setting *required* in the ``[app:MyProject]`` |
| | | section unless you've changed the callable referred to by the |
| | | ``egg:MyProject`` entry point to accept more arguments: other settings you |
| | | add to this section are passed as keywords arguments to the callable |
| | | add to this section are passed as keyword arguments to the callable |
| | | represented by this entry point (``main`` in our ``__init__.py`` module). |
| | | You can provide startup-time configuration parameters to your application by |
| | | adding more settings to this section. |
| | | |
| | | The ``reload_templates`` setting in the ``[app:MyProject]`` section is a |
| | | :app:`Pyramid` -specific setting which is passed into the framework. If it |
| | | The ``pyramid.reload_templates`` setting in the ``[app:MyProject]`` section is |
| | | a :app:`Pyramid` -specific setting which is passed into the framework. If it |
| | | exists, and its value is ``true``, :term:`Chameleon` and :term:`Mako` |
| | | template changes will not require an application restart to be detected. See |
| | | :ref:`reload_templates_section` for more information. |
| | | |
| | | The ``debug_templates`` setting in the ``[app:MyProject]`` section is a |
| | | The ``pyramid.debug_templates`` setting in the ``[app:MyProject]`` section is a |
| | | :app:`Pyramid` -specific setting which is passed into the framework. If it |
| | | exists, and its value is ``true``, :term:`Chameleon` template exceptions will |
| | | contained more detailed and helpful information about the error than when |
| | | contain more detailed and helpful information about the error than when |
| | | this value is ``false``. See :ref:`debug_templates_section` for more |
| | | information. |
| | | |
| | | .. warning:: The ``reload_templates`` and ``debug_templates`` options should |
| | | be turned off for production applications, as template rendering is slowed |
| | | when either is turned on. |
| | | .. warning:: The ``pyramid.reload_templates`` and ``pyramid.debug_templates`` |
| | | options should be turned off for production applications, as template |
| | | rendering is slowed when either is turned on. |
| | | |
| | | The ``pyramid.include`` setting in the ``[app:MyProject]`` section tells |
| | | Pyramid to "include" configuration from another package. In this case, the |
| | | line ``pyramid.include = pyramid_debugtoolbar`` tells Pyramid to include |
| | | configuration from the ``pyramid_debugtoolbar`` package. This turns on a |
| | | debugging panel in development mode which will be shown on the right hand |
| | | side of the screen. Including the debug toolbar will also make it possible |
| | | to interactively debug exceptions when an error occurs. |
| | | |
| | | Various other settings may exist in this section having to do with debugging |
| | | or influencing runtime behavior of a :app:`Pyramid` application. See |
| | |
| | | application be nonblocking as all application code will run in its own |
| | | thread, provided by the server you're using. |
| | | |
| | | The sections that live between the markers ``# Begin logging configuration`` |
| | | and ``# End logging configuration`` represent Python's standard library |
| | | :mod:`logging` module configuration for your application. The sections |
| | | between these two markers are passed to the `logging module's config file |
| | | configuration engine |
| | | <http://docs.python.org/howto/logging.html#configuring-logging>`_ when the |
| | | ``paster serve`` or ``paster pshell`` commands are executed. The default |
| | | configuration sends application logging output to the standard error output |
| | | of your terminal. |
| | | |
| | | See the :term:`PasteDeploy` documentation for more information about other |
| | | types of things you can put into this ``.ini`` file, such as other |
| | | applications, :term:`middleware` and alternate :term:`WSGI` server |
| | |
| | | to your application's ``main`` function as ``global_config`` (see |
| | | the reference to the ``main`` function in :ref:`init_py`). |
| | | |
| | | .. index:: |
| | | single: production.ini |
| | | |
| | | ``production.ini`` |
| | | ~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | The ``production.ini`` file is a :term:`PasteDeploy` configuration file with |
| | | a purpose much like that of ``development.ini``. However, it disables the |
| | | WebError interactive debugger, replacing it with a logger which outputs |
| | | exception messages to ``stderr`` by default. It also turns off template |
| | | development options such that templates are not automatically reloaded when |
| | | changed, and turns off all debugging options. You can use this file instead |
| | | of ``development.ini`` when you put your application into production. |
| | | debug toolbar, replacing it with a logger which outputs exception messages to |
| | | ``stderr`` by default. It also turns off template development options such |
| | | that templates are not automatically reloaded when changed, and turns off all |
| | | debugging options. It allows you to configure a ``weberror#error_catcher`` |
| | | section that will cause exceptions to be sent to an email address when they |
| | | are uncaught. You can use this file instead of ``development.ini`` when you |
| | | put your application into production. |
| | | |
| | | .. index:: |
| | | single: MANIFEST.in |
| | |
| | | setuptools add-on such as ``setuptools-git`` or ``setuptools-hg`` for this |
| | | behavior to work properly. |
| | | |
| | | .. index:: |
| | | single: setup.cfg |
| | | |
| | | ``setup.cfg`` |
| | | ~~~~~~~~~~~~~ |
| | | |
| | |
| | | Line 12 returns a :term:`WSGI` application to the caller of the function |
| | | (Paste). |
| | | |
| | | .. index:: |
| | | single: views.py |
| | | |
| | | ``views.py`` |
| | | ~~~~~~~~~~~~ |
| | | |
| | |
| | | See :ref:`views_which_use_a_renderer` for more information about how views, |
| | | renderers, and templates relate and cooperate. |
| | | |
| | | .. note:: Because our ``development.ini`` has a ``reload_templates = |
| | | .. note:: Because our ``development.ini`` has a ``pyramid.reload_templates = |
| | | true`` directive indicating that templates should be reloaded when |
| | | they change, you won't need to restart the application server to |
| | | see changes you make to templates. During development, this is |
| | | handy. If this directive had been ``false`` (or if the directive |
| | | did not exist), you would need to restart the application server |
| | | for each template change. For production applications, you should |
| | | set your project's ``reload_templates`` to ``false`` to increase |
| | | set your project's ``pyramid.reload_templates`` to ``false`` to increase |
| | | the speed at which templates may be rendered. |
| | | |
| | | .. index:: |
| | |
| | | application uses an instance of :class:`myproject.resources.Root` to |
| | | represent the root. |
| | | |
| | | .. index:: |
| | | single: static directory |
| | | |
| | | ``static`` |
| | | ~~~~~~~~~~ |
| | | |
| | |
| | | ``templates/mytemplate.pt`` |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | The single :term:`Chameleon` template exists in the project. Its contents |
| | | The single :term:`Chameleon` template that exists in the project. Its contents |
| | | are too long to show here, but it displays a default page when rendered. It |
| | | is referenced by the call to ``add_view`` as the ``renderer`` attribute in |
| | | the ``__init__`` file. See :ref:`views_which_use_a_renderer` for more |
| | |
| | | |
| | | See :ref:`testing_chapter` for more information about writing :app:`Pyramid` |
| | | unit tests. |
| | | |
| | | .. index:: |
| | | pair: modifying; package structure |
| | | |
| | | .. _modifying_package_structure: |
| | | |
| | |
| | | argument which accepts a :term:`dotted Python name` or direct object |
| | | reference. |
| | | |
| | | Using the Interactive Shell |
| | | --------------------------- |
| | | |
| | | It is possible to use a Python interpreter prompt loaded with a similar |
| | | configuration as would be loaded if you were running your Pyramid application |
| | | via ``paster serve``. This can be a useful debugging tool. See |
| | | :ref:`interactive_shell` for more details. |
| | | |
| | | |
| | | |
| | |
| | | Renderers |
| | | ========= |
| | | |
| | | A view needn't *always* return a :term:`Response` object. If a view |
| | | happens to return something which does not implement the Pyramid |
| | | Response interface, :app:`Pyramid` will attempt to use a |
| | | :term:`renderer` to construct a response. For example: |
| | | A view callable needn't *always* return a :term:`Response` object. If a view |
| | | happens to return something which does not implement the Pyramid Response |
| | | interface, :app:`Pyramid` will attempt to use a :term:`renderer` to construct |
| | | a response. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | using the api of the ``request.response`` attribute. See |
| | | :ref:`request_response_attr`. |
| | | |
| | | .. index:: |
| | | pair: renderer; JSONP |
| | | |
| | | .. _jsonp_renderer: |
| | | |
| | | JSONP Renderer |
| | |
| | | ``templates`` directory of the ``mypackage`` package. |
| | | |
| | | The ``Mako`` template renderer can take additional arguments beyond the |
| | | standard ``reload_templates`` setting, see the :ref:`environment_chapter` for |
| | | additional :ref:`mako_template_renderer_settings`. |
| | | standard ``pyramid.reload_templates`` setting, see the |
| | | :ref:`environment_chapter` for additional |
| | | :ref:`mako_template_renderer_settings`. |
| | | |
| | | .. index:: |
| | | single: response headers (from a renderer) |
| | |
| | | returning various values in the ``response_headerlist``, this is purely a |
| | | convenience. |
| | | |
| | | .. index:: |
| | | single: renderer (adding) |
| | | |
| | | .. _adding_and_overriding_renderers: |
| | | |
| | | Adding and Changing Renderers |
| | |
| | | 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 |
| | | name` referring to such an object. |
| | | |
| | | .. index:: |
| | | pair: renderer; adding |
| | | |
| | | .. _adding_a_renderer: |
| | | |
| | |
| | | to the ``MyJinja2Renderer`` constructor will be the full value that was |
| | | set as ``renderer=`` in the view configuration. |
| | | |
| | | .. index:: |
| | | pair: renderer; changing |
| | | |
| | | Changing an Existing Renderer |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | |
| | | config.add_renderer(None, 'mypackage.json_renderer_factory') |
| | | |
| | | .. index:: |
| | | pair: renderer; overriding at runtime |
| | | |
| | | Overriding A Renderer At Runtime |
| | | -------------------------------- |
| | | |
| | |
| | | For more information about generating resource URLs, see the documentation |
| | | for :func:`pyramid.url.resource_url`. |
| | | |
| | | .. index:: |
| | | pair: resource URL generation; overriding |
| | | |
| | | .. _overriding_resource_url_generation: |
| | | |
| | | Overriding Resource URL Generation |
| | |
| | | anchor elements (only path elements) to work best with |
| | | :func:`~pyramid.url.resource_url`. |
| | | |
| | | .. index:: |
| | | single: resource path generation |
| | | |
| | | Generating the Path To a Resource |
| | | --------------------------------- |
| | | |
| | |
| | | |
| | | The presence or absence of a :term:`virtual root` has no impact on the |
| | | behavior of :func:`~pyramid.traversal.resource_path`. |
| | | |
| | | .. index:: |
| | | pair: resource; finding by path |
| | | |
| | | Finding a Resource by Path |
| | | -------------------------- |
| | |
| | | |
| | | See the :func:`pyramid.traversal.find_resource` documentation for more |
| | | information about resolving a path to a resource. |
| | | |
| | | .. index:: |
| | | pair: resource; lineage |
| | | |
| | | Obtaining the Lineage of a Resource |
| | | ----------------------------------- |
| | |
| | | parent (or one of its parent's parents, etc.) is an ancestor. |
| | | |
| | | See :func:`pyramid.location.inside` for more information. |
| | | |
| | | .. index:: |
| | | pair: resource; finding root |
| | | |
| | | Finding the Root Resource |
| | | ------------------------- |
| | |
| | | For more information about how resource interfaces can be used by view |
| | | configuration, see :ref:`using_resource_interfaces`. |
| | | |
| | | .. index:: |
| | | pair: resource; finding by interface or class |
| | | |
| | | Finding a Resource With a Class or Interface in Lineage |
| | | ------------------------------------------------------- |
| | | |
| | |
| | | single: request processing |
| | | single: request |
| | | single: router |
| | | single: request lifecycle |
| | | |
| | | .. _router_chapter: |
| | | |
| | |
| | | to invoke the ``blog_entry_add_view`` view. If he does not, the |
| | | :term:`Forbidden view` will be invoked. |
| | | |
| | | .. index:: |
| | | pair: permission; default |
| | | |
| | | .. _setting_a_default_permission: |
| | | |
| | | Setting a Default Permission |
| | |
| | | permission is ignored for that view registration, and the |
| | | view-configuration-named permission is used. |
| | | |
| | | - If a view configuration names an explicit permission as the string |
| | | ``__no_permission_required__``, the default permission is ignored, |
| | | and the view is registered *without* a permission (making it |
| | | - If a view configuration names the permission |
| | | :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission |
| | | is ignored, and the view is registered *without* a permission (making it |
| | | available to all callers regardless of their credentials). |
| | | |
| | | .. warning:: |
| | |
| | | When you register a default permission, *all* views (even :term:`exception |
| | | view` views) are protected by a permission. For all views which are truly |
| | | meant to be anonymously accessible, you will need to associate the view's |
| | | configuration with the ``__no_permission_required__`` permission. |
| | | configuration with the :data:`pyramid.security.NO_PERMISSION_REQUIRED` |
| | | permission. |
| | | |
| | | .. index:: |
| | | single: ACL |
| | | single: access control list |
| | | pair: resource; ACL |
| | | |
| | | .. _assigning_acls: |
| | | |
| | |
| | | authentication information. |
| | | |
| | | This behavior can also be turned on in the application ``.ini`` file |
| | | by setting the ``debug_authorization`` key to ``true`` within the |
| | | by setting the ``pyramid.debug_authorization`` key to ``true`` within the |
| | | application's configuration section, e.g.: |
| | | |
| | | .. code-block:: ini |
| | |
| | | |
| | | [app:main] |
| | | use = egg:MyProject#app |
| | | debug_authorization = true |
| | | 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. |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | class AuthenticationPolicy(object): |
| | | class IAuthenticationPolicy(object): |
| | | """ An object representing a Pyramid authentication policy. """ |
| | | |
| | | def authenticated_userid(self, request): |
| | |
| | | retrieve data from sessions, and two session-specific features: flash |
| | | messages, and cross-site request forgery attack prevention. |
| | | |
| | | .. index:: |
| | | single: session factory (default) |
| | | |
| | | .. _using_the_default_session_factory: |
| | | |
| | | Using The Default Session Factory |
| | |
| | | session factory implementation (preferably one which keeps session data on |
| | | the server) for anything but the most basic of applications where "session |
| | | security doesn't matter". |
| | | |
| | | .. index:: |
| | | single: session object |
| | | |
| | | Using a Session Object |
| | | ---------------------- |
| | |
| | | .. index:: |
| | | single: pyramid_beaker |
| | | single: Beaker |
| | | single: session factory (alternates) |
| | | |
| | | .. _using_alternate_session_factories: |
| | | |
| | |
| | | ``pyramid_beaker``. |
| | | |
| | | .. index:: |
| | | single: session factory |
| | | single: session factory (custom) |
| | | |
| | | Creating Your Own Session Factory |
| | | --------------------------------- |
| | |
| | | log messages for single-time display without having direct access to an HTML |
| | | template. The user interface consists of a number of methods of the |
| | | :term:`session` object. |
| | | |
| | | .. index:: |
| | | single: session.flash |
| | | |
| | | Using the ``session.flash`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | ``False``, and you attempt to add a message value which is already |
| | | present in the queue, it will not be added. |
| | | |
| | | .. index:: |
| | | single: session.pop_flash |
| | | |
| | | Using the ``session.pop_flash`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | ['info message'] |
| | | >>> request.session.pop_flash() |
| | | [] |
| | | |
| | | .. index:: |
| | | single: session.peek_flash |
| | | |
| | | Using the ``session.peek_flash`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | `Cross-site request forgery |
| | | <http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a |
| | | phenomenon whereby a user with an identity on your website might click on a |
| | | URL or button on another website which unwittingly redirects the user to your |
| | | URL or button on another website which secretly redirects the user to your |
| | | application to perform some command that requires elevated privileges. |
| | | |
| | | You can avoid most of these attacks by making sure that the correct *CSRF |
| | |
| | | post. To use CSRF token support, you must enable a :term:`session factory` |
| | | as described in :ref:`using_the_default_session_factory` or |
| | | :ref:`using_alternate_session_factories`. |
| | | |
| | | .. index:: |
| | | single: session.get_csrf_token |
| | | |
| | | Using the ``session.get_csrf_token`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | if token != request.POST['csrf_token']: |
| | | raise ValueError('CSRF token did not match') |
| | | |
| | | .. index:: |
| | | single: session.new_csrf_token |
| | | |
| | | Using the ``session.new_csrf_token`` Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | that particular composite to understand how to make it refer to your |
| | | :app:`Pyramid` application. |
| | | |
| | | #. The PasteDeploy framework finds all :mod:`logging` related configuration |
| | | in the ``.ini`` file and uses it to configure the Python standard library |
| | | logging system for this application. |
| | | |
| | | #. The application's *constructor* (named by the entry point reference or |
| | | dotted Python name on the ``use=`` line of the section representing your |
| | | :app:`Pyramid` application) is passed the key/value parameters mentioned |
| | |
| | | In this case, the ``myproject.__init__:main`` function referred to by the |
| | | entry point URI ``egg:MyProject`` (see :ref:`MyProject_ini` for more |
| | | information about entry point URIs, and how they relate to callables), |
| | | will receive the key/value pairs ``{'reload_templates':'true', |
| | | 'debug_authorization':'false', 'debug_notfound':'false', |
| | | 'debug_routematch':'false', 'debug_templates':'true', |
| | | 'default_locale_name':'en'}``. |
| | | will receive the key/value pairs ``{'pyramid.reload_templates':'true', |
| | | 'pyramid.debug_authorization':'false', 'pyramid.debug_notfound':'false', |
| | | 'pyramid.debug_routematch':'false', 'pyramid.debug_templates':'true', |
| | | 'pyramid.default_locale_name':'en'}``. |
| | | |
| | | #. The ``main`` function first constructs a |
| | | :class:`~pyramid.config.Configurator` instance, passing a root resource |
| | |
| | | |
| | | The ``settings`` dictionary contains all the options in the |
| | | ``[app:MyProject]`` section of our .ini file except the ``use`` option |
| | | (which is internal to Paste) such as ``reload_templates``, |
| | | ``debug_authorization``, etc. |
| | | (which is internal to Paste) such as ``pyramid.reload_templates``, |
| | | ``pyramid.debug_authorization``, etc. |
| | | |
| | | #. The ``main`` function then calls various methods on the an instance of the |
| | | class :class:`~pyramid.config.Configurator` method. The intent of |
| | | calling these methods is to populate an :term:`application registry`, |
| | | which represents the :app:`Pyramid` configuration related to the |
| | | application. |
| | | #. The ``main`` function then calls various methods on the instance of the |
| | | class :class:`~pyramid.config.Configurator` created in the previous step. |
| | | The intent of calling these methods is to populate an |
| | | :term:`application registry`, which represents the :app:`Pyramid` |
| | | configuration related to the application. |
| | | |
| | | #. The :meth:`~pyramid.config.Configurator.make_wsgi_app` method is called. |
| | | The result is a :term:`router` instance. The router is associated with |
| | |
| | | The server serves the application, and the application is running, waiting |
| | | to receive requests. |
| | | |
| | | .. index:: |
| | | pair: settings; deployment |
| | | single: custom settings |
| | | |
| | | .. _deployment_settings: |
| | | |
| | | Deployment Settings |
| | |
| | | single: renderer (template) |
| | | |
| | | |
| | | .. index:: |
| | | pair: renderer; system values |
| | | |
| | | .. _renderer_system_values: |
| | | |
| | | System Values Used During Rendering |
| | |
| | | renderer itself, but most template renderers, including Chameleon and |
| | | Mako renderers, make these names available as top-level template |
| | | variables. |
| | | |
| | | .. index:: |
| | | pair: renderer; templates |
| | | |
| | | .. _templates_used_as_renderers: |
| | | |
| | |
| | | renderers, including Chameleon ZPT renderers. |
| | | |
| | | .. index:: |
| | | single: sample template |
| | | single: ZPT template (sample) |
| | | |
| | | A Sample ZPT Template |
| | | ~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | <body> |
| | | <h1 class="title">Welcome to <code>${project}</code>, an |
| | | application generated by the <a |
| | | href="http://docs.pylonsproject.org/projects/pyramid/dev/" |
| | | href="http://docs.pylonsproject.org/projects/pyramid/current/" |
| | | >pyramid</a> web |
| | | application framework.</h1> |
| | | </body> |
| | |
| | | extension and my Chameleon text template files with a ``.txt`` |
| | | extension so that these ``svn:ignore`` patterns work. |
| | | |
| | | .. index:: |
| | | pair: debugging; templates |
| | | |
| | | .. _debug_templates_section: |
| | | |
| | | Nicer Exceptions in Chameleon Templates |
| | |
| | | $ PYRAMID_DEBUG_TEMPLATES=1 bin/paster serve myproject.ini |
| | | |
| | | To use a setting in the application ``.ini`` file for the same |
| | | purpose, set the ``debug_templates`` key to ``true`` within the |
| | | application's configuration section, e.g.: |
| | | purpose, set the ``pyramid.debug_templates`` key to ``true`` within |
| | | the application's configuration section, e.g.: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | | |
| | | [app:MyProject] |
| | | use = egg:MyProject#app |
| | | debug_templates = true |
| | | pyramid.debug_templates = true |
| | | |
| | | With template debugging off, a :exc:`NameError` exception resulting |
| | | from rendering a template with an undefined variable |
| | |
| | | |
| | | .. note:: |
| | | |
| | | Turning on ``debug_templates`` has the same effect as using the |
| | | Turning on ``pyramid.debug_templates`` has the same effect as using the |
| | | Chameleon environment variable ``CHAMELEON_DEBUG``. See `Chameleon |
| | | Environment Variables |
| | | <http://chameleon.repoze.org/docs/latest/config.html#environment-variables>`_ |
| | |
| | | ``mako.directories`` setting and other Mako-related settings that can be |
| | | placed into the application's ``ini`` file. |
| | | |
| | | .. index:: |
| | | single: Mako template (sample) |
| | | |
| | | A Sample Mako Template |
| | | ~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | <body> |
| | | <h1 class="title">Welcome to <code>${project}</code>, an |
| | | application generated by the <a |
| | | href="http://docs.pylonsproject.org/projects/pyramid/dev/" |
| | | href="http://docs.pylonsproject.org/projects/pyramid/current/" |
| | | >pyramid</a> web application framework.</h1> |
| | | </body> |
| | | </html> |
| | |
| | | $ PYRAMID_RELOAD_TEMPLATES=1 bin/paster serve myproject.ini |
| | | |
| | | To use a setting in the application ``.ini`` file for the same |
| | | purpose, set the ``reload_templates`` key to ``true`` within the |
| | | purpose, set the ``pyramid.reload_templates`` key to ``true`` within the |
| | | application's configuration section, e.g.: |
| | | |
| | | .. code-block:: ini |
| | |
| | | |
| | | [app:main] |
| | | use = egg:MyProject#app |
| | | reload_templates = true |
| | | pyramid.reload_templates = true |
| | | |
| | | .. index:: |
| | | single: template system bindings |
| | |
| | | -specific request attributes are also available as described in |
| | | :ref:`special_request_attributes`. |
| | | |
| | | .. index:: |
| | | single: resource interfaces |
| | | |
| | | .. _using_resource_interfaces: |
| | | |
| | | Using Resource Interfaces In View Configuration |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | Instead of registering your views with a ``context`` that names a Python |
| | | resource *class*, you can optionally register a view callable with a |
| | | ``context`` which is an :term:`interface`. An interface can be attached |
| | | arbitrarily to any resource object. View lookup treats context interfaces |
| | | specially, and therefore the identity of a resource can be divorced from that |
| | | of the class which implements it. As a result, associating a view with an |
| | | interface can provide more flexibility for sharing a single view between two |
| | | or more different implementations of a resource type. For example, if two |
| | | resource objects of different Python class types share the same interface, |
| | | you can use the same view configuration to specify both of them as a |
| | | ``context``. |
| | | |
| | | In order to make use of interfaces in your application during view dispatch, |
| | | you must create an interface and mark up your resource classes or instances |
| | | with interface declarations that refer to this interface. |
| | | |
| | | To attach an interface to a resource *class*, you define the interface and |
| | | use the :func:`zope.interface.implements` function to associate the interface |
| | | with the class. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from zope.interface import Interface |
| | | from zope.interface import implements |
| | | |
| | | class IHello(Interface): |
| | | """ A marker interface """ |
| | | |
| | | class Hello(object): |
| | | implements(IHello) |
| | | |
| | | To attach an interface to a resource *instance*, you define the interface and |
| | | use the :func:`zope.interface.alsoProvides` function to associate the |
| | | interface with the instance. This function mutates the instance in such a |
| | | way that the interface is attached to it. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from zope.interface import Interface |
| | | from zope.interface import alsoProvides |
| | | |
| | | class IHello(Interface): |
| | | """ A marker interface """ |
| | | |
| | | class Hello(object): |
| | | pass |
| | | |
| | | def make_hello(): |
| | | hello = Hello() |
| | | alsoProvides(hello, IHello) |
| | | return hello |
| | | |
| | | Regardless of how you associate an interface, with a resource instance, or a |
| | | resource class, the resulting code to associate that interface with a view |
| | | callable is the same. Assuming the above code that defines an ``IHello`` |
| | | interface lives in the root of your application, and its module is named |
| | | "resources.py", the interface declaration below will associate the |
| | | ``mypackage.views.hello_world`` view with resources that implement, or |
| | | provide, this interface. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | # config is an instance of pyramid.config.Configurator |
| | | |
| | | config.add_view('mypackage.views.hello_world', name='hello.html', |
| | | context='mypackage.resources.IHello') |
| | | |
| | | Any time a resource that is determined to be the :term:`context` provides |
| | | this interface, and a view named ``hello.html`` is looked up against it as |
| | | per the URL, the ``mypackage.views.hello_world`` view callable will be |
| | | invoked. |
| | | |
| | | Note, in cases where a view is registered against a resource class, and a |
| | | view is also registered against an interface that the resource class |
| | | implements, an ambiguity arises. Views registered for the resource class take |
| | | precedence over any views registered for any interface the resource class |
| | | implements. Thus, if one view configuration names a ``context`` of both the |
| | | class type of a resource, and another view configuration names a ``context`` |
| | | of interface implemented by the resource's class, and both view |
| | | configurations are otherwise identical, the view registered for the context's |
| | | class will "win". |
| | | |
| | | For more information about defining resources with interfaces for use within |
| | | view configuration, see :ref:`resources_which_implement_interfaces`. |
| | | |
| | | |
| | | References |
| | | ---------- |
| | | |
| | |
| | | URL Dispatch |
| | | ============ |
| | | |
| | | :term:`URL dispatch` provides a simple way to map URLs to :term:`view` |
| | | code using a simple pattern matching language. An ordered set of |
| | | patterns is checked one-by-one. If one of the patterns matches the path |
| | | information associated with a request, a particular :term:`view |
| | | callable` is invoked. |
| | | |
| | | :term:`URL dispatch` is one of two ways to perform :term:`resource |
| | | location` in :app:`Pyramid`; the other way is using :term:`traversal`. |
| | | If no route is matched using :term:`URL dispatch`, :app:`Pyramid` falls |
| | | back to :term:`traversal` to handle the :term:`request`. |
| | | |
| | | It is the responsibility of the :term:`resource location` subsystem |
| | | (i.e., :term:`URL dispatch` or :term:`traversal`) to find the resource |
| | | object that is the :term:`context` of the :term:`request`. Once the |
| | | :term:`context` is determined, :term:`view lookup` is then responsible |
| | | for finding and invoking a :term:`view callable`. A view callable is a |
| | | specific bit of code, defined in your application, that receives the |
| | | :term:`request` and returns a :term:`response` object. |
| | | |
| | | Where appropriate, we will describe how view lookup interacts with |
| | | :term:`resource location`. The :ref:`view_config_chapter` chapter describes |
| | | the details of :term:`view lookup`. |
| | | :term:`URL dispatch` provides a simple way to map URLs to :term:`view` code |
| | | using a simple pattern matching language. An ordered set of patterns is |
| | | checked one-by-one. If one of the patterns matches the path information |
| | | associated with a request, a particular :term:`view callable` is invoked. A |
| | | view callable is a specific bit of code, defined in your application, that |
| | | receives the :term:`request` and returns a :term:`response` object. |
| | | |
| | | High-Level Operational Overview |
| | | ------------------------------- |
| | |
| | | matching patterns present in a *route map*. |
| | | |
| | | If any route pattern matches the information in the :term:`request`, |
| | | :app:`Pyramid` will invoke :term:`view lookup` using a :term:`context` |
| | | resource generated by the route match. |
| | | :app:`Pyramid` will invoke :term:`view lookup` to find a matching view. |
| | | |
| | | However, if no route pattern matches the information in the :term:`request` |
| | | provided to :app:`Pyramid`, it will fail over to using :term:`traversal` to |
| | | perform resource location and view lookup. |
| | | If no route pattern in the route map matches the information in the |
| | | :term:`request` provided in your application, :app:`Pyramid` will fail over |
| | | to using :term:`traversal` to perform resource location and view lookup. |
| | | |
| | | Technically, URL dispatch is a :term:`resource location` mechanism (it finds |
| | | a context object). But ironically, using URL dispatch (instead of |
| | | :term:`traversal`) allows you to avoid thinking about your application in |
| | | terms of "resources" entirely, because it allows you to directly map a |
| | | :term:`view callable` to a route. |
| | | .. index:: |
| | | single: route configuration |
| | | |
| | | Route Configuration |
| | | ------------------- |
| | |
| | | |
| | | .. _config-add-route: |
| | | |
| | | Configuring a Route via The ``add_route`` Configurator Method |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | Configuring a Route to Match a View |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | The :meth:`pyramid.config.Configurator.add_route` method adds a single |
| | | :term:`route configuration` to the :term:`application registry`. Here's an |
| | |
| | | config.add_route('myroute', '/prefix/{one}/{two}') |
| | | config.add_view(myview, route_name='myroute') |
| | | |
| | | .. versionchanged:: 1.0a4 |
| | | Prior to 1.0a4, routes allow for a marker starting with a ``:``, for |
| | | example ``/prefix/:one/:two``. This style is now deprecated |
| | | in favor of ``{}`` usage which allows for additional functionality. |
| | | When a :term:`view callable` added to the configuration by way of |
| | | :meth:`~pyramid.config.Configurator.add_view` bcomes associated with a route |
| | | via its ``route_name`` predicate, that view callable will always be found and |
| | | invoked when the associated route pattern matches during a request. |
| | | |
| | | .. index:: |
| | | single: route configuration; view callable |
| | | |
| | | .. _add_route_view_config: |
| | | |
| | | Route Configuration That Names a View Callable |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | .. warning:: This section describes a feature which has been deprecated in |
| | | Pyramid 1.1 and higher. In order to reduce confusion and documentation |
| | | burden, passing view-related parameters to |
| | | :meth:`~pyramid.config.Configurator.add_route` is deprecated. |
| | | |
| | | In versions earlier than 1.1, a view was permitted to be connected to a |
| | | route using a set of ``view*`` parameters passed to the |
| | | :meth:`~pyramid.config.Configurator.add_route`. This was a shorthand |
| | | which replaced the need to perform a subsequent call to |
| | | :meth:`~pyramid.config.Configurator.add_view` as described in |
| | | :ref:`config-add-route`. For example, it was valid (and often recommended) |
| | | to do: |
| | | |
| | | .. code-block:: python |
| | | |
| | | config.add_route('home', '/', view='mypackage.views.myview', |
| | | view_renderer='some/renderer.pt') |
| | | |
| | | Instead of the equivalent: |
| | | |
| | | .. code-block:: python |
| | | |
| | | config.add_route('home', '/') |
| | | config.add_view('mypackage.views.myview', route_name='home') |
| | | renderer='some/renderer.pt') |
| | | |
| | | Passing ``view*`` arguments to ``add_route`` as shown in the first |
| | | example above is now deprecated in favor of connecting a view to a |
| | | predefined route via :meth:`~pyramid.config.Configurator.add_view` using |
| | | the route's ``route_name`` parameter, as shown in the second example |
| | | above. |
| | | |
| | | A deprecation warning is now issued when any view-related parameter is |
| | | passed to ``Configurator.add_route``. The recommended way to associate a |
| | | view with a route is documented in :ref:`config-add-route`. |
| | | |
| | | When a route configuration declaration names a ``view`` attribute, the value |
| | | of the attribute will reference a :term:`view callable`. This view callable |
| | | will be invoked when the route matches. A view callable, as described in |
| | | :ref:`views_chapter`, is developer-supplied code that "does stuff" as the |
| | | result of a request. |
| | | |
| | | Here's an example route configuration that references a view callable: |
| | | More commonly, you will not use any ``add_view`` statements in your project's |
| | | "setup" code, instead only using ``add_route`` statements using a |
| | | :term:`scan` for to associate view callables with routes. For example, if |
| | | this is a portion of your project's ``__init__.py``: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | # "config" below is presumed to be an instance of the |
| | | # pyramid.config.Configurator class; "myview" is assumed |
| | | # to be a "view callable" function |
| | | from myproject.views import myview |
| | | config.add_route('myroute', '/prefix/{one}/{two}', view=myview) |
| | | # in your project's __init__.py (mypackage.__init__) |
| | | |
| | | You can also pass a :term:`dotted Python name` as the ``view`` argument |
| | | rather than an actual callable: |
| | | 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 |
| | | ``config.scan('mypackage')`` will pick up all :term:`configuration |
| | | decoration`, including any objects decorated with the |
| | | :class:`pyramid.view.view_config` decorator in the ``mypackage`` Python |
| | | pakage. For example, if you have a ``views.py`` in your package, a scan will |
| | | pick up any of its configuration decorators, so we can add one there that |
| | | that references ``myroute`` as a ``route_name`` parameter: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | # "config" below is presumed to be an instance of the |
| | | # pyramid.config.Configurator class; "myview" is assumed |
| | | # to be a "view callable" function |
| | | config.add_route('myroute', '/prefix/{one}/{two}', |
| | | view='myproject.views.myview') |
| | | # in your project's views.py module (mypackage.views) |
| | | |
| | | When a route configuration names a ``view`` attribute, the :term:`view |
| | | callable` named as that ``view`` attribute will always be found and invoked |
| | | when the associated route pattern matches during a request. |
| | | from pyramid.view import view_config |
| | | from pyramid.response import Response |
| | | |
| | | See :meth:`pyramid.config.Configurator.add_route` for a description of |
| | | view-related arguments. |
| | | @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``. |
| | | |
| | | .. index:: |
| | | single: route path pattern syntax |
| | |
| | | |
| | | Route configuration declarations are evaluated in a specific order when a |
| | | request enters the system. As a result, the order of route configuration |
| | | declarations is very important. |
| | | |
| | | The order that routes declarations are evaluated is the order in which they |
| | | are added to the application at startup time. This is unlike |
| | | :term:`traversal`, which depends on emergent behavior which happens as a |
| | | result of traversing a resource tree. |
| | | declarations is very important. The order that routes declarations are |
| | | evaluated is the order in which they are added to the application at startup |
| | | time. (This is unlike a different way of mapping URLs to code that |
| | | :app:`Pyramid` provides, named :term:`traversal`, which does not depend on |
| | | pattern ordering). |
| | | |
| | | For routes added via the :mod:`~pyramid.config.Configurator.add_route` method, |
| | | the order that routes are evaluated is the order in which they are added to |
| | |
| | | combine URL dispatch with :term:`traversal` as documented within |
| | | :ref:`hybrid_chapter`. |
| | | |
| | | .. index:: |
| | | single: route configuration arguments |
| | | |
| | | Route Configuration Arguments |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | process. Examples of route predicate arguments are ``pattern``, ``xhr``, and |
| | | ``request_method``. |
| | | |
| | | Other arguments are view configuration related arguments. These only have an |
| | | effect when the route configuration names a ``view``. These arguments have |
| | | been deprecated as of :app:`Pyramid` 1.1 (see :ref:`add_route_view_config`). |
| | | |
| | | Other arguments are ``name`` and ``factory``. These arguments represent |
| | | neither predicates nor view configuration information. |
| | | |
| | | .. warning:: Some arguments are view-configuration related arguments, such as |
| | | ``view_renderer``. These only have an effect when the route configuration |
| | | names a ``view`` and these arguments have been deprecated as of |
| | | :app:`Pyramid` 1.1. |
| | | |
| | | .. index:: |
| | | single: route predicates (custom) |
| | | |
| | | .. _custom_route_predicates: |
| | | |
| | |
| | | See also :class:`pyramid.interfaces.IRoute` for more API documentation about |
| | | route objects. |
| | | |
| | | .. index:: |
| | | single: route matching |
| | | |
| | | Route Matching |
| | | -------------- |
| | | |
| | | The main purpose of route configuration is to match (or not match) the |
| | | ``PATH_INFO`` present in the WSGI environment provided during a request |
| | | against a URL path pattern. |
| | | against a URL path pattern. ``PATH_INFO`` represents the path portion of the |
| | | URL that was requested. |
| | | |
| | | The way that :app:`Pyramid` does this is very simple. When a request enters |
| | | the system, for each route configuration declaration present in the system, |
| | | :app:`Pyramid` checks the ``PATH_INFO`` against the pattern declared. |
| | | |
| | | If any route matches, the route matching process stops. The :term:`request` |
| | | is decorated with a special :term:`interface` which describes it as a "route |
| | | request", the :term:`context` resource is generated, and the context and the |
| | | resulting request are handed off to :term:`view lookup`. During view lookup, |
| | | if a :term:`view callable` associated with the matched route is found, that |
| | | view is called. |
| | | :app:`Pyramid` checks the request's ``PATH_INFO`` against the pattern |
| | | declared. This checking happens in the order that the routes were declared |
| | | via :meth:`pyramid.config.Configurator.add_route`. |
| | | |
| | | When a route configuration is declared, it may contain :term:`route |
| | | predicate` arguments. All route predicates associated with a route |
| | | declaration must be ``True`` for the route configuration to be used for a |
| | | given request. |
| | | given request during a check. If any predicate in the set of :term:`route |
| | | predicate` arguments provided to a route configuration returns ``False`` |
| | | during a check, that route is skipped and route matching continues through |
| | | the ordered set of routes. |
| | | |
| | | If any predicate in the set of :term:`route predicate` arguments provided to |
| | | a route configuration returns ``False``, that route is skipped and route |
| | | matching continues through the ordered set of routes. |
| | | If any route matches, the route matching process stops and the :term:`view |
| | | lookup` subsystem takes over to find the most reasonable view callable for |
| | | the matched route. Most often, there's only one view that will match (a view |
| | | configured with a ``route_name`` argument matching the matched route). To |
| | | gain a better understanding of how routes and views are associated in a real |
| | | application, you can use the ``paster pviews`` command, as documented in |
| | | :ref:`displaying_matching_views`. |
| | | |
| | | If no route matches after all route patterns are exhausted, :app:`Pyramid` |
| | | falls back to :term:`traversal` to do :term:`resource location` and |
| | |
| | | single: matching the root URL |
| | | single: root url (matching) |
| | | |
| | | .. index:: |
| | | pair: matching; root URL |
| | | |
| | | Matching the Root URL |
| | | --------------------- |
| | | |
| | |
| | | calling convention of ``(context, request)`` (``context`` will be the |
| | | exception object). |
| | | |
| | | .. index:: |
| | | single: cleaning up after request |
| | | |
| | | .. _cleaning_up_after_a_request: |
| | | |
| | | Cleaning Up After a Request |
| | |
| | | .. note:: See :ref:`security_chapter` for more information about |
| | | :app:`Pyramid` security and ACLs. |
| | | |
| | | .. index:: |
| | | pair: debugging; route matching |
| | | |
| | | .. _debug_routematch_section: |
| | | |
| | | Debugging Route Matching |
| | |
| | | It's useful to be able to take a peek under the hood when requests that enter |
| | | your application arent matching your routes as you expect them to. To debug |
| | | route matching, use the ``PYRAMID_DEBUG_ROUTEMATCH`` environment variable or the |
| | | ``debug_routematch`` configuration file setting (set either to ``true``). |
| | | ``pyramid.debug_routematch`` configuration file setting (set either to ``true``). |
| | | Details of the route matching decision for a particular request to the |
| | | :app:`Pyramid` application will be printed to the ``stderr`` of the console |
| | | which you started the application from. For example: |
| | |
| | | See :ref:`environment_chapter` for more information about how, and where to |
| | | set these values. |
| | | |
| | | You can also use the ``paster proutes`` command to see a display of all the |
| | | routes configured in your application; for more information, see |
| | | :ref:`displaying_application_routes`. |
| | | |
| | | .. index:: |
| | | pair: routes; printing |
| | | single: paster proutes |
| | | |
| | | .. _displaying_application_routes: |
| | | |
| | | Displaying All Application Routes |
| | | --------------------------------- |
| | | |
| | | You can use the ``paster proutes`` command in a terminal window to print a |
| | | summary of routes related to your application. Much like the ``paster |
| | | pshell`` command (see :ref:`interactive_shell`), the ``paster proutes`` |
| | | command accepts two arguments. The first argument to ``proutes`` is the path |
| | | to your application's ``.ini`` file. The second is the ``app`` section name |
| | | inside the ``.ini`` file which points to your application. |
| | | |
| | | For example: |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | |
| | | [chrism@thinko MyProject]$ ../bin/paster proutes development.ini MyProject |
| | | Name Pattern View |
| | | ---- ------- ---- |
| | | home / <function my_view> |
| | | home2 / <function my_view> |
| | | another /another None |
| | | static/ static/*subpath <static_view object> |
| | | catchall /*subpath <function static_view> |
| | | |
| | | ``paster proutes`` generates a table. The table has three columns: a Name |
| | | name column, a Pattern column, and a View column. The items listed in the |
| | | Name column are route names, the items listen in the Pattern column are route |
| | | patterns, and the items listed in the View column are representations of the |
| | | view callable that will be invoked when a request matches the associated |
| | | route pattern. The view column may show ``None`` if no associated view |
| | | callable could be found. If no routes are configured within your |
| | | application, nothing will be printed to the console when ``paster proutes`` |
| | | is executed. |
| | | pair: route; view callable lookup details |
| | | |
| | | Route View Callable Registration and Lookup Details |
| | | --------------------------------------------------- |
| | |
| | | object is decorated with the route-specific interface. |
| | | |
| | | - The fact that the request is decorated with a route-specific interface |
| | | causes the view lookup machinery to always use the view callable registered |
| | | using that interface by the route configuration to service requests that |
| | | match the route pattern. |
| | | causes the :term:`view lookup` machinery to always use the view callable |
| | | registered using that interface by the route configuration to service |
| | | requests that match the route pattern. |
| | | |
| | | In this way, we supply a shortcut to the developer. Under the hood, the |
| | | :term:`resource location` and :term:`view lookup` subsystems provided by |
| | | :app:`Pyramid` are still being utilized, but in a way which does not require |
| | | a developer to understand either of them in detail. It also means that we |
| | | can allow a developer to combine :term:`URL dispatch` and :term:`traversal` |
| | | in various exceptional cases as documented in :ref:`hybrid_chapter`. |
| | | As we can see from the above description, technically, URL dispatch doesn't |
| | | actually map a URL pattern directly to a view callable. Instead, URL |
| | | dispatch is a :term:`resource location` mechanism. A :app:`Pyramid` |
| | | :term:`resource location` subsystem (i.e., :term:`URL dispatch` or |
| | | :term:`traversal`) finds a :term:`resource` object that is the |
| | | :term:`context` of a :term:`request`. Once the :term:`context` is determined, |
| | | a separate subsystem named :term:`view lookup` is then responsible for |
| | | finding and invoking a :term:`view callable` based on information available |
| | | in the context and the request. When URL dispatch is used, the resource |
| | | location and view lookup subsystems provided by :app:`Pyramid` are still |
| | | being utilized, but in a way which does not require a developer to understand |
| | | either of them in detail. |
| | | |
| | | To gain a better understanding of how routes and views are associated in a |
| | | real application, you can use the ``paster pviews`` command, as documented |
| | | in :ref:`displaying_matching_views`. |
| | | If no route is matched using :term:`URL dispatch`, :app:`Pyramid` falls back |
| | | to :term:`traversal` to handle the :term:`request`. |
| | | |
| | | References |
| | | ---------- |
| | | |
| | | A tutorial showing how :term:`URL dispatch` can be used to create a |
| | | :app:`Pyramid` application exists in :ref:`bfg_sql_wiki_tutorial`. |
| | | |
| | |
| | | a URL "prefix", as well as serving a *portion* of a :term:`traversal` |
| | | based application under a root URL. |
| | | |
| | | .. index:: |
| | | single: hosting an app under a prefix |
| | | |
| | | Hosting an Application Under a URL Prefix |
| | | ----------------------------------------- |
| | | |
| | |
| | | |
| | | .. _view_configuration: |
| | | |
| | | .. _view_lookup: |
| | | |
| | | View Configuration |
| | | ================== |
| | | |
| | | .. index:: |
| | | single: view lookup |
| | | |
| | | :term:`View configuration` controls how :term:`view lookup` operates in |
| | | your application. In earlier chapters, you have been exposed to a few |
| | | simple view configuration declarations without much explanation. In this |
| | | chapter we will explore the subject in detail. |
| | | |
| | | .. _view_lookup: |
| | | |
| | | View Lookup and Invocation |
| | | -------------------------- |
| | | |
| | | :term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding |
| | | an invoking a :term:`view callable`. The view lookup subsystem is passed a |
| | | :term:`context` and a :term:`request` object. |
| | | and invoking a :term:`view callable`. :term:`View configuration` controls how |
| | | :term:`view lookup` operates in your application. During any given request, |
| | | view configuration information is compared against request data by the view |
| | | lookup subsystem in order to find the "best" view callable for that request. |
| | | |
| | | :term:`View configuration` information stored within in the |
| | | :term:`application registry` is compared against the context and request by |
| | | the view lookup subsystem in order to find the "best" view callable for the |
| | | set of circumstances implied by the context and request. |
| | | In earlier chapters, you have been exposed to a few simple view configuration |
| | | declarations without much explanation. In this chapter we will explore the |
| | | subject in detail. |
| | | |
| | | :term:`View predicate` attributes are an important part of view |
| | | configuration that enables the :term:`View lookup` subsystem to find and |
| | | invoke the appropriate view. Predicate attributes can be thought of |
| | | like "narrowers". In general, the greater number of predicate |
| | | attributes possessed by a view's configuration, the more specific the |
| | | circumstances need to be before the registered view callable will be |
| | | invoked. |
| | | .. index:: |
| | | pair: resource; mapping to view callable |
| | | pair: URL pattern; mapping to view callable |
| | | |
| | | Mapping a Resource or URL Pattern to a View Callable |
| | | ---------------------------------------------------- |
| | |
| | | A view configuration statement is made about information present in the |
| | | :term:`context` resource and the :term:`request`. |
| | | |
| | | View configuration is performed in one of these ways: |
| | | View configuration is performed in one of two ways: |
| | | |
| | | - by running a :term:`scan` against application source code which has a |
| | | :class:`pyramid.view.view_config` decorator attached to a Python object as |
| | |
| | | - by using the :meth:`pyramid.config.Configurator.add_view` method as per |
| | | :ref:`mapping_views_using_imperative_config_section`. |
| | | |
| | | - By specifying a view within a :term:`route configuration`. View |
| | | configuration via a route configuration is performed by using the |
| | | :meth:`pyramid.config.Configurator.add_route` method, passing a ``view`` |
| | | argument specifying a view callable. This pattern of view configuration is |
| | | deprecated as of :app:`Pyramid` 1.1. |
| | | |
| | | .. note:: A package named ``pyramid_handlers`` (available from PyPI) provides |
| | | an analogue of :term:`Pylons` -style "controllers", which are a special |
| | | kind of view class which provides more automation when your application |
| | | uses :term:`URL dispatch` solely. |
| | | .. index:: |
| | | single: view configuration parameters |
| | | |
| | | .. _view_configuration_parameters: |
| | | |
| | |
| | | to narrow the set of circumstances in which :term:`view lookup` will find a |
| | | particular view callable. |
| | | |
| | | In general, the fewer number of predicates which are supplied to a |
| | | particular view configuration, the more likely it is that the associated |
| | | view callable will be invoked. The greater the number supplied, the |
| | | less likely. A view with five predicates will always be found and |
| | | evaluated before a view with two, for example. All predicates must |
| | | match for the associated view to be called. |
| | | :term:`View predicate` attributes are an important part of view configuration |
| | | that enables the :term:`view lookup` subsystem to find and invoke the |
| | | appropriate view. The greater number of predicate attributes possessed by a |
| | | view's configuration, the more specific the circumstances need to be before |
| | | the registered view callable will be invoked. The fewer number of predicates |
| | | which are supplied to a particular view configuration, the more likely it is |
| | | that the associated view callable will be invoked. A view with five |
| | | predicates will always be found and evaluated before a view with two, for |
| | | example. All predicates must match for the associated view to be called. |
| | | |
| | | This does not mean however, that :app:`Pyramid` "stops looking" when it |
| | | finds a view registration with predicates that don't match. If one set |
| | |
| | | representing a "not found" (404) page. See :ref:`changing_the_notfound_view` |
| | | for more information about changing the default notfound view. |
| | | |
| | | Some view configuration arguments are non-predicate arguments. These tend to |
| | | modify the response of the view callable or prevent the view callable from |
| | | Other view configuration arguments are non-predicate arguments. These tend |
| | | to modify the response of the view callable or prevent the view callable from |
| | | being invoked due to an authorization policy. The presence of non-predicate |
| | | arguments in a view configuration does not narrow the circumstances in which |
| | | the view callable will be invoked. |
| | | |
| | | .. _nonpredicate_view_args: |
| | | |
| | | Non-Predicate Arguments |
| | | +++++++++++++++++++++++ |
| | |
| | | configured view. |
| | | |
| | | ``name`` |
| | | The :term:`view name` required to match this view callable. Read |
| | | :ref:`traversal_chapter` to understand the concept of a view name. |
| | | The :term:`view name` required to match this view callable. A ``name`` |
| | | argument is typically only used when your application uses |
| | | :term:`traversal`. Read :ref:`traversal_chapter` to understand the concept |
| | | of a view name. |
| | | |
| | | If ``name`` is not supplied, the empty string is used (implying the default |
| | | view). |
| | |
| | | |
| | | .. _mapping_views_using_a_decorator_section: |
| | | |
| | | View Configuration Using the ``@view_config`` Decorator |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | For better locality of reference, you may use the |
| | | :class:`pyramid.view.view_config` decorator to associate your view functions |
| | | with URLs instead of using imperative configuration for the same purpose. |
| | | Adding View Configuration Using the ``@view_config`` Decorator |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | .. warning:: |
| | | |
| | | Using this feature tends to slows down application startup slightly, as |
| | | more work is performed at application startup to scan for view |
| | | declarations. |
| | | configuration declarations. For maximum startup performance, use the view |
| | | configuration method described in |
| | | :ref:`mapping_views_using_imperative_config_section` instead. |
| | | |
| | | Usage of the ``view_config`` decorator is a form of :term:`declarative |
| | | configuration` in decorator form. :class:`~pyramid.view.view_config` can be |
| | | used to associate :term:`view configuration` information -- as done via the |
| | | equivalent imperative code -- with a function that acts as a :app:`Pyramid` |
| | | view callable. All arguments to the |
| | | :meth:`pyramid.config.Configurator.add_view` method (save for the ``view`` |
| | | argument) are available in decorator form and mean precisely the same thing. |
| | | The :class:`~pyramid.view.view_config` decorator can be used to associate |
| | | :term:`view configuration` information with a function, method, or class that |
| | | acts as a :app:`Pyramid` view callable. |
| | | |
| | | An example of the :class:`~pyramid.view.view_config` decorator might reside in |
| | | a :app:`Pyramid` application module ``views.py``: |
| | | Here's an example of the :class:`~pyramid.view.view_config` decorator that |
| | | lives within a :app:`Pyramid` application module ``views.py``: |
| | | |
| | | .. ignore-next-block |
| | | .. code-block:: python |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.response import Response |
| | | |
| | | @view_config(name='my_view', request_method='POST', context=MyResource, |
| | | permission='read') |
| | | @view_config(route_name='ok', request_method='POST', permission='read') |
| | | def my_view(request): |
| | | return Response('OK') |
| | | |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | config.add_view('mypackage.views.my_view', name='my_view', |
| | | request_method='POST', context=MyResource, |
| | | 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: |
| | | |
| | |
| | | allows you to supply a ``package`` argument to better control exactly *which* |
| | | code will be scanned. |
| | | |
| | | All arguments to the :class:`~pyramid.view.view_config` decorator mean |
| | | precisely the same thing as they would if they were passed as arguments to |
| | | the :meth:`pyramid.config.Configurator.add_view` method save for the ``view`` |
| | | argument. Usage of the :class:`~pyramid.view.view_config` decorator is a |
| | | form of :term:`declarative configuration`, while |
| | | :meth:`pyramid.config.Configurator.add_view` is a form of :term:`imperative |
| | | configuration`. However, they both do the same thing. |
| | | |
| | | .. index:: |
| | | single: view_config placement |
| | | |
| | | ``@view_config`` Placement |
| | | ++++++++++++++++++++++++++ |
| | | |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.response import Response |
| | | |
| | | @view_config(name='edit') |
| | | @view_config(route_name='edit') |
| | | def edit(request): |
| | | return Response('edited!') |
| | | |
| | |
| | | from pyramid.response import Response |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config() |
| | | @view_config(route_name='hello') |
| | | class MyView(object): |
| | | def __init__(self, request): |
| | | self.request = request |
| | |
| | | def __call__(self): |
| | | return Response('hello') |
| | | |
| | | my_view = view_config()(MyView) |
| | | my_view = view_config(route_name='hello')(MyView) |
| | | |
| | | 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 |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.response import Response |
| | | |
| | | @view_config(name='edit') |
| | | @view_config(name='change') |
| | | @view_config(route_name='edit') |
| | | @view_config(route_name='change') |
| | | def edit(request): |
| | | return Response('edited!') |
| | | |
| | |
| | | def __init__(self, request): |
| | | self.request = request |
| | | |
| | | @view_config(name='hello') |
| | | @view_config(route_name='hello') |
| | | def amethod(self): |
| | | return Response('hello') |
| | | |
| | |
| | | from pyramid.response import Response |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config(attr='amethod', name='hello') |
| | | @view_config(attr='amethod', route_name='hello') |
| | | class MyView(object): |
| | | def __init__(self, request): |
| | | self.request = request |
| | |
| | | |
| | | .. _mapping_views_using_imperative_config_section: |
| | | |
| | | View Registration Using :meth:`~pyramid.config.Configurator.add_view` |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | Adding View Configuration Using :meth:`~pyramid.config.Configurator.add_view` |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | The :meth:`pyramid.config.Configurator.add_view` method within |
| | | :ref:`configuration_module` is used to configure a view imperatively. The |
| | | arguments to this method are very similar to the arguments that you provide |
| | | to the ``@view_config`` decorator. For example: |
| | | :ref:`configuration_module` is used to configure a view "imperatively" |
| | | (without a :class:`~pyramid.view.view_config` decorator). The arguments to |
| | | this method are very similar to the arguments that you provide to the |
| | | :class:`~pyramid.view.view_config` decorator. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | # config is assumed to be an instance of the |
| | | # pyramid.config.Configurator class |
| | | config.add_view(hello_world, name='hello.html') |
| | | config.add_view(hello_world, route_name='hello') |
| | | |
| | | The first argument, ``view``, is required. It must either be a Python object |
| | | which is the view itself or a :term:`dotted Python name` to such an object. |
| | | All other arguments are optional. See |
| | | :meth:`pyramid.config.Configurator.add_view` for more information. |
| | | In the above example, ``view`` is the ``hello_world`` function. All other |
| | | arguments are optional. See :meth:`pyramid.config.Configurator.add_view` for |
| | | more information. |
| | | |
| | | .. index:: |
| | | single: resource interfaces |
| | | |
| | | .. _using_resource_interfaces: |
| | | |
| | | Using Resource Interfaces In View Configuration |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | Instead of registering your views with a ``context`` that names a Python |
| | | resource *class*, you can optionally register a view callable with a |
| | | ``context`` which is an :term:`interface`. An interface can be attached |
| | | arbitrarily to any resource object. View lookup treats context interfaces |
| | | specially, and therefore the identity of a resource can be divorced from that |
| | | of the class which implements it. As a result, associating a view with an |
| | | interface can provide more flexibility for sharing a single view between two |
| | | or more different implementations of a resource type. For example, if two |
| | | resource objects of different Python class types share the same interface, |
| | | you can use the same view configuration to specify both of them as a |
| | | ``context``. |
| | | |
| | | In order to make use of interfaces in your application during view dispatch, |
| | | you must create an interface and mark up your resource classes or instances |
| | | with interface declarations that refer to this interface. |
| | | |
| | | To attach an interface to a resource *class*, you define the interface and |
| | | use the :func:`zope.interface.implements` function to associate the interface |
| | | with the class. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from zope.interface import Interface |
| | | from zope.interface import implements |
| | | |
| | | class IHello(Interface): |
| | | """ A marker interface """ |
| | | |
| | | class Hello(object): |
| | | implements(IHello) |
| | | |
| | | To attach an interface to a resource *instance*, you define the interface and |
| | | use the :func:`zope.interface.alsoProvides` function to associate the |
| | | interface with the instance. This function mutates the instance in such a |
| | | way that the interface is attached to it. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from zope.interface import Interface |
| | | from zope.interface import alsoProvides |
| | | |
| | | class IHello(Interface): |
| | | """ A marker interface """ |
| | | |
| | | class Hello(object): |
| | | pass |
| | | |
| | | def make_hello(): |
| | | hello = Hello() |
| | | alsoProvides(hello, IHello) |
| | | return hello |
| | | |
| | | Regardless of how you associate an interface, with a resource instance, or a |
| | | resource class, the resulting code to associate that interface with a view |
| | | callable is the same. Assuming the above code that defines an ``IHello`` |
| | | interface lives in the root of your application, and its module is named |
| | | "resources.py", the interface declaration below will associate the |
| | | ``mypackage.views.hello_world`` view with resources that implement, or |
| | | provide, this interface. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | # config is an instance of pyramid.config.Configurator |
| | | |
| | | config.add_view('mypackage.views.hello_world', name='hello.html', |
| | | context='mypackage.resources.IHello') |
| | | |
| | | Any time a resource that is determined to be the :term:`context` provides |
| | | this interface, and a view named ``hello.html`` is looked up against it as |
| | | per the URL, the ``mypackage.views.hello_world`` view callable will be |
| | | invoked. |
| | | |
| | | Note, in cases where a view is registered against a resource class, and a |
| | | view is also registered against an interface that the resource class |
| | | implements, an ambiguity arises. Views registered for the resource class take |
| | | precedence over any views registered for any interface the resource class |
| | | implements. Thus, if one view configuration names a ``context`` of both the |
| | | class type of a resource, and another view configuration names a ``context`` |
| | | of interface implemented by the resource's class, and both view |
| | | configurations are otherwise identical, the view registered for the context's |
| | | class will "win". |
| | | |
| | | For more information about defining resources with interfaces for use within |
| | | view configuration, see :ref:`resources_which_implement_interfaces`. |
| | | When you use only :meth:`~pyramid.config.Configurator.add_view` to add view |
| | | configurations, you don't need to issue a :term:`scan` in order for the view |
| | | configuration to take effect. |
| | | |
| | | .. index:: |
| | | single: view security |
| | |
| | | |
| | | # config is an instance of pyramid.config.Configurator |
| | | |
| | | config.add_view('myproject.views.add_entry', name='add.html', |
| | | context='myproject.resources.IBlog', 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 |
| | |
| | | It's useful to be able to debug :exc:`NotFound` error responses when they |
| | | occur unexpectedly due to an application registry misconfiguration. To debug |
| | | these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the |
| | | ``debug_notfound`` configuration file setting. Details of why a view was not |
| | | found will be printed to ``stderr``, and the browser representation of the |
| | | error will include the same information. See :ref:`environment_chapter` for |
| | | more information about how, and where to set these values. |
| | | ``pyramid.debug_notfound`` configuration file setting. Details of why a view |
| | | was not found will be printed to ``stderr``, and the browser representation of |
| | | the error will include the same information. See :ref:`environment_chapter` |
| | | for more information about how, and where to set these values. |
| | | |
| | | .. index:: |
| | | pair: matching views; printing |
| | | single: paster pviews |
| | | single: HTTP caching |
| | | |
| | | .. _displaying_matching_views: |
| | | .. _influencing_http_caching: |
| | | |
| | | Displaying Matching Views for a Given URL |
| | | ----------------------------------------- |
| | | Influencing HTTP Caching |
| | | ------------------------ |
| | | |
| | | For a big application with several views, it can be hard to keep the view |
| | | configuration details in your head, even if you defined all the views |
| | | yourself. You can use the ``paster pviews`` command in a terminal window to |
| | | print a summary of matching routes and views for a given URL in your |
| | | application. The ``paster pviews`` command accepts three arguments. The |
| | | first argument to ``pviews`` is the path to your application's ``.ini`` file. |
| | | The second is the ``app`` section name inside the ``.ini`` file which points |
| | | to your application. The third is the URL to test for matching views. |
| | | .. note:: This feature is new in Pyramid 1.1. |
| | | |
| | | Here is an example for a simple view configuration using :term:`traversal`: |
| | | When a non-``None`` ``http_cache`` argument is passed to a view |
| | | configuration, Pyramid will set ``Expires`` and ``Cache-Control`` response |
| | | headers in the resulting response, causing browsers to cache the response |
| | | data for some time. See ``http_cache`` in :ref:`nonpredicate_view_args` for |
| | | the its allowable values and what they mean. |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | Sometimes it's undesirable to have these headers set as the result of |
| | | returning a response from a view, even though you'd like to decorate the view |
| | | with a view configuration decorator that has ``http_cache``. Perhaps there's |
| | | an alternate branch in your view code that returns a response that should |
| | | never be cacheable, while the "normal" branch returns something that should |
| | | always be cacheable. If this is the case, set the ``prevent_auto`` attribute |
| | | of the ``response.cache_control`` object to a non-``False`` value. For |
| | | example, the below view callable is configured with a ``@view_config`` |
| | | decorator that indicates any response from the view should be cached for 3600 |
| | | seconds. However, the view itself prevents caching from taking place unless |
| | | there's a ``should_cache`` GET or POST variable: |
| | | |
| | | $ ../bin/paster pviews development.ini tutorial /FrontPage |
| | | .. code-block:: python |
| | | |
| | | URL = /FrontPage |
| | | from pyramid.view import view_config |
| | | |
| | | context: <tutorial.models.Page object at 0xa12536c> |
| | | view name: |
| | | @view_config(http_cache=3600) |
| | | def view(request): |
| | | response = Response() |
| | | if not 'should_cache' in request.params: |
| | | response.cache_control.prevent_auto = True |
| | | return response |
| | | |
| | | View: |
| | | ----- |
| | | tutorial.views.view_page |
| | | required permission = view |
| | | Note that the ``http_cache`` machinery will overwrite or add to caching |
| | | headers you set within the view itself unless you use ``preserve_auto``. |
| | | |
| | | 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 view matches, so there is just a single *View* section. For each |
| | | matching view, the full code path to the associated view callable is shown, |
| | | along with any permissions and predicates that are part of that view |
| | | configuration. |
| | | You can also turn of the effect of ``http_cache`` entirely for the duration |
| | | of a Pyramid application lifetime. To do so, set the |
| | | ``PYRAMID_PREVENT_HTTP_CACHE`` environment variable or the |
| | | ``pyramid.prevent_http_cache`` configuration value setting to a true value. |
| | | For more information, see :ref:`preventing_http_caching`. |
| | | |
| | | A more complex configuration might generate something like this: |
| | | Note that setting ``pyramid.prevent_http_cache`` will have no effect on caching |
| | | headers that your application code itself sets. It will only prevent caching |
| | | headers that would have been set by the Pyramid HTTP caching machinery |
| | | invoked as the result of the ``http_cache`` argument to view configuration. |
| | | |
| | | .. code-block:: text |
| | | :linenos: |
| | | .. index:: |
| | | pair: view configuration; debugging |
| | | |
| | | $ ../bin/paster pviews development.ini shootout /about |
| | | Debugging View Configuration |
| | | ---------------------------- |
| | | |
| | | 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 |
| | | displayed first, followed by any views that are associated with that route. |
| | | As you can see from the second matching route output, a route can be |
| | | associated with more than one view. |
| | | |
| | | For a URL that doesn't match any views, ``paster pviews`` will simply print |
| | | out a *Not found* message. |
| | | |
| | | See :ref:`displaying_matching_views` for information about how to display |
| | | each of the view callables that might match for a given URL. This can be an |
| | | effective way to figure out why a particular view callable is being called |
| | | instead of the one you'd like to be called. |
| | |
| | | Views |
| | | ===== |
| | | |
| | | One of the primary jobs of :app:`Pyramid` is to find and invoke a |
| | | :term:`view callable` when a :term:`request` reaches your application. View |
| | | callables are bits of code which do something interesting in response to a |
| | | request made to your application. |
| | | One of the primary jobs of :app:`Pyramid` is to find and invoke a :term:`view |
| | | callable` when a :term:`request` reaches your application. View callables |
| | | are bits of code which do something interesting in response to a request made |
| | | to your application. They are the "meat" of any interesting web application. |
| | | |
| | | .. note:: |
| | | |
| | |
| | | that implements a view *callable*, and the process of view |
| | | *lookup*. |
| | | |
| | | The :ref:`urldispatch_chapter`, and :ref:`traversal_chapter` chapters |
| | | describes how, using information from the :term:`request`, a |
| | | :term:`context` resource is computed. But the context resource itself |
| | | isn't very useful without an associated :term:`view callable`. A view |
| | | callable returns a response to a user, often using the context resource |
| | | to do so. |
| | | This chapter describes how view callables should be defined. We'll have to |
| | | wait until a following chapter (entitled :ref:`view_config_chapter`) to find |
| | | out how we actually tell :app:`Pyramid` to wire up view callables to |
| | | particular URL patterns and other request circumstances. |
| | | |
| | | The job of actually locating and invoking the "best" :term:`view callable` is |
| | | the job of the :term:`view lookup` subsystem. The view lookup subsystem |
| | | compares the resource supplied by :term:`resource location` and information |
| | | in the :term:`request` against :term:`view configuration` statements made by |
| | | the developer to choose the most appropriate view callable for a specific |
| | | set of circumstances. |
| | | |
| | | This chapter describes how view callables work. In the |
| | | :ref:`view_config_chapter` chapter, there are details about performing |
| | | view configuration, and a detailed explanation of view lookup. |
| | | .. index:: |
| | | single: view callables |
| | | |
| | | View Callables |
| | | -------------- |
| | | |
| | | View callables are, at the risk of sounding obvious, callable Python |
| | | objects. Specifically, view callables can be functions, classes, or |
| | | instances that implement an ``__call__`` method (making the |
| | | instance callable). |
| | | objects. Specifically, view callables can be functions, classes, or instances |
| | | that implement an ``__call__`` method (making the instance callable). |
| | | |
| | | View callables must, at a minimum, accept a single argument named |
| | | ``request``. This argument represents a :app:`Pyramid` :term:`Request` |
| | | object. A request object encapsulates a WSGI environment provided to |
| | | :app:`Pyramid` by the upstream :term:`WSGI` server. As you might expect, |
| | | the request object contains everything your application needs to know |
| | | about the specific HTTP request being made. |
| | | object. A request object represents a :term:`WSGI` environment provided to |
| | | :app:`Pyramid` by the upstream WSGI server. As you might expect, the request |
| | | object contains everything your application needs to know about the specific |
| | | HTTP request being made. |
| | | |
| | | A view callable's ultimate responsibility is to create a :mod:`Pyramid` |
| | | :term:`Response` object. This can be done by creating the response object in |
| | | the view callable code and returning it directly, as we will be doing in this |
| | | chapter. However, if a view callable does not return a response itself, it |
| | | can be configured to use a :term:`renderer` that converts its return value |
| | | into a :term:`Response` object. Using renderers is the common way that |
| | | templates are used with view callables to generate markup: see the |
| | | :ref:`renderers_chapter` chapter for details. In some cases, a response may |
| | | also be generated by raising an exception within a view callable. |
| | | :term:`Response` object. This can be done by creating a :term:`Response` |
| | | object in the view callable code and returning it directly or by raising |
| | | special kinds of exceptions from within the body of a view callable. |
| | | |
| | | .. index:: |
| | | single: view calling convention |
| | |
| | | method of the class if you'd like the class to represent a collection of |
| | | related view callables. |
| | | |
| | | .. note:: A package named :term:`pyramid_handlers` (available from PyPI) |
| | | provides an analogue of :term:`Pylons` -style "controllers", which are a |
| | | special kind of view class which provides more automation when your |
| | | application uses :term:`URL dispatch` solely. |
| | | |
| | | .. index:: |
| | | single: view calling convention |
| | | |
| | | .. _request_and_context_view_definitions: |
| | | |
| | | Alternate View Callable Argument/Calling Conventions |
| | | ---------------------------------------------------- |
| | | |
| | | Usually, view callables are defined to accept only a single argument: |
| | | ``request``. However, view callables may alternately be defined as classes, |
| | | functions, or any callable that accept *two* positional arguments: a |
| | | :term:`context` resource as the first argument and a :term:`request` as the |
| | | second argument. |
| | | |
| | | The :term:`context` and :term:`request` arguments passed to a view function |
| | | defined in this style can be defined as follows: |
| | | |
| | | context |
| | | |
| | | The :term:`resource` object found via tree :term:`traversal` or :term:`URL |
| | | dispatch`. |
| | | |
| | | request |
| | | A :app:`Pyramid` Request object representing the current WSGI request. |
| | | |
| | | The following types work as view callables in this style: |
| | | |
| | | #. Functions that accept two arguments: ``context``, and ``request``, |
| | | e.g.: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | def view(context, request): |
| | | return Response('OK') |
| | | |
| | | #. Classes that have an ``__init__`` method that accepts ``context, |
| | | request`` and a ``__call__`` method which accepts no arguments, e.g.: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | class view(object): |
| | | def __init__(self, context, request): |
| | | self.context = context |
| | | self.request = request |
| | | |
| | | def __call__(self): |
| | | return Response('OK') |
| | | |
| | | #. Arbitrary callables that have a ``__call__`` method that accepts |
| | | ``context, request``, e.g.: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | 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 |
| | | callable code itself. |
| | | |
| | | No matter which view calling convention is used, the view code always has |
| | | access to the context via ``request.context``. |
| | | |
| | | .. index:: |
| | | single: view response |
| | | single: response |
| | |
| | | inherit from :class:`pyramid.response.Response`. For example, an instance of |
| | | the class :class:`pyramid.httpexceptions.HTTPFound` is also a valid response |
| | | object because it inherits from :class:`~pyramid.response.Response`. For |
| | | examples, see :ref:`http_exceptions` and ref:`http_redirect`. |
| | | examples, see :ref:`http_exceptions` and :ref:`http_redirect`. |
| | | |
| | | You can also return objects from view callables that aren't instances of (or |
| | | instances of classes which are subclasses of) |
| | | :class:`pyramid.response.Response` in various circumstances. This can be |
| | | helpful when writing tests and when attempting to share code between view |
| | | callables. See :ref:`renderers_chapter` for the common way to allow for |
| | | this. A much less common way to allow for view callables to return |
| | | non-Response objects is documented in :ref:`using_iresponse`. |
| | | .. note:: |
| | | |
| | | You can also return objects from view callables that aren't instances of |
| | | :class:`pyramid.response.Response` in various circumstances. This can be |
| | | helpful when writing tests and when attempting to share code between view |
| | | callables. See :ref:`renderers_chapter` for the common way to allow for |
| | | this. A much less common way to allow for view callables to return |
| | | non-Response objects is documented in :ref:`using_iresponse`. |
| | | |
| | | .. index:: |
| | | single: view exceptions |
| | |
| | | always part of a :term:`view`. For a general overview of how to handle form |
| | | submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and |
| | | `"Query and POST variables" within the WebOb documentation |
| | | <http://pythonpaste.org/webob/reference.html#query-post-variables>`_. |
| | | <http://docs.webob.org/en/latest/reference.html#query-post-variables>`_. |
| | | :app:`Pyramid` defers to WebOb for its request and response implementations, |
| | | and handling form submission data is a property of the request |
| | | implementation. Understanding WebOb's request API is the key to |
| | |
| | | configuration. The keys are still (byte) strings. |
| | | |
| | | |
| | | .. index:: |
| | | single: view calling convention |
| | | |
| | | .. _request_and_context_view_definitions: |
| | | |
| | | Alternate View Callable Argument/Calling Conventions |
| | | ---------------------------------------------------- |
| | | |
| | | Usually, view callables are defined to accept only a single argument: |
| | | ``request``. However, view callables may alternately be defined as classes, |
| | | functions, or any callable that accept *two* positional arguments: a |
| | | :term:`context` resource as the first argument and a :term:`request` as the |
| | | second argument. |
| | | |
| | | The :term:`context` and :term:`request` arguments passed to a view function |
| | | defined in this style can be defined as follows: |
| | | |
| | | context |
| | | |
| | | The :term:`resource` object found via tree :term:`traversal` or :term:`URL |
| | | dispatch`. |
| | | |
| | | request |
| | | A :app:`Pyramid` Request object representing the current WSGI request. |
| | | |
| | | The following types work as view callables in this style: |
| | | |
| | | #. Functions that accept two arguments: ``context``, and ``request``, |
| | | e.g.: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | def view(context, request): |
| | | return Response('OK') |
| | | |
| | | #. Classes that have an ``__init__`` method that accepts ``context, |
| | | request`` and a ``__call__`` method which accepts no arguments, e.g.: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | class view(object): |
| | | def __init__(self, context, request): |
| | | self.context = context |
| | | self.request = request |
| | | |
| | | def __call__(self): |
| | | return Response('OK') |
| | | |
| | | #. Arbitrary callables that have a ``__call__`` method that accepts |
| | | ``context, request``, e.g.: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | 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 |
| | | callable code itself. |
| | | |
| | | No matter which view calling convention is used, the view code always has |
| | | access to the context via ``request.context``. |
| | | |
| | | .. index:: |
| | | single: Pylons-style controller dispatch |
| | | |
| | | Pylons-1.0-Style "Controller" Dispatch |
| | | -------------------------------------- |
| | | |
| | | A package named :term:`pyramid_handlers` (available from PyPI) provides an |
| | | analogue of :term:`Pylons` -style "controllers", which are a special kind of |
| | | view class which provides more automation when your application uses |
| | | :term:`URL dispatch` solely. |
| | | |
| | |
| | | |
| | | WebOb is a project separate from :app:`Pyramid` with a separate set of |
| | | authors and a fully separate `set of documentation |
| | | <http://pythonpaste.org/webob/>`_. Pyramid adds some functionality to the |
| | | standard WebOb request, which is documented in the :ref:`request_module` API |
| | | documentation. |
| | | <http://docs.webob.org/en/latest/index.html>`_. Pyramid adds some |
| | | functionality to the standard WebOb request, which is documented in the |
| | | :ref:`request_module` API documentation. |
| | | |
| | | WebOb provides objects for HTTP requests and responses. Specifically it does |
| | | this by wrapping the `WSGI <http://wsgi.org>`_ request environment and |
| | |
| | | WSGI requests and responses; however, we won't cover that use case in this |
| | | document, as users of :app:`Pyramid` don't typically need to use the |
| | | WSGI-related features of WebOb directly. The `reference documentation |
| | | <http://pythonpaste.org/webob/reference.html>`_ shows many examples of |
| | | <http://docs.webob.org/en/latest/reference.html>`_ shows many examples of |
| | | creating requests and using response objects in this manner, however. |
| | | |
| | | .. index:: |
| | |
| | | ``POST`` that is *not* a form submission, or a request like a |
| | | ``PUT``. You can also get ``req.body_file`` for a file-like |
| | | object. |
| | | |
| | | ``req.json_body`` |
| | | The JSON-decoded contents of the body of the request. See |
| | | :ref:`request_json_body`. |
| | | |
| | | ``req.cookies``: |
| | | A simple dictionary of all the cookies. |
| | |
| | | API documentation for a multidict exists as |
| | | :class:`pyramid.interfaces.IMultiDict`. |
| | | |
| | | .. index:: |
| | | pair: json_body; request |
| | | |
| | | .. _request_json_body: |
| | | |
| | | Dealing With A JSON-Encoded Request Body |
| | | ++++++++++++++++++++++++++++++++++++++++ |
| | | |
| | | .. note:: this feature is new as of Pyramid 1.1. |
| | | |
| | | :attr:`pyramid.request.Request.json_body` is a property that returns a |
| | | :term:`JSON` -decoded representation of the request body. If the request |
| | | does not have a body, or the body is not a properly JSON-encoded value, an |
| | | exception will be raised when this attribute is accessed. |
| | | |
| | | This attribute is useful when you invoke a Pyramid view callable via |
| | | e.g. jQuery's ``$.ajax`` function, which has the potential to send a request |
| | | with a JSON-encoded body. |
| | | |
| | | Using ``request.json_body`` is equivalent to: |
| | | |
| | | .. code-block:: python |
| | | |
| | | 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 to a Pyramid application: |
| | | |
| | | .. code-block:: javascript |
| | | |
| | | jQuery.ajax({type:'POST', |
| | | url: 'http://localhost:6543/', // the pyramid server |
| | | data: JSON.stringify({'a':1}), |
| | | contentType: 'application/json; charset=utf-8'}); |
| | | |
| | | When such a request reaches a view in your application, the |
| | | ``request.json_body`` attribute will be available in the view callable body. |
| | | |
| | | .. code-block:: javascript |
| | | |
| | | @view_config(renderer='string') |
| | | def aview(request): |
| | | print request.json_body |
| | | return 'OK' |
| | | |
| | | For the above view, printed to the console will be: |
| | | |
| | | .. code-block:: python |
| | | |
| | | {u'a': 1} |
| | | |
| | | For bonus points, here's a bit of client-side code that will produce a |
| | | request that has a body suitable for reading via ``request.json_body`` using |
| | | Python's ``urllib2`` instead of a Javascript AJAX request: |
| | | |
| | | .. code-block:: python |
| | | |
| | | import urllib2 |
| | | import json |
| | | |
| | | json_payload = json.dumps({'a':1}) |
| | | headers = {'Content-Type':'application/json; charset=utf-8'} |
| | | req = urllib2.Request('http://localhost:6543/', json_payload, headers) |
| | | resp = urllib2.urlopen(req) |
| | | |
| | | More Details |
| | | ++++++++++++ |
| | | |
| | |
| | | |
| | | - The :class:`pyramid.request.Request` API documentation. |
| | | |
| | | - The `WebOb documentation <http://pythonpaste.org/webob>`_. All |
| | | methods and attributes of a ``webob.Request`` documented within the |
| | | - The `WebOb documentation <http://docs.webob.org/en/latest/index.html>`_. |
| | | All methods and attributes of a ``webob.Request`` documented within the |
| | | WebOb documentation will work with request objects created by |
| | | :app:`Pyramid`. |
| | | |
| | |
| | | ``response.last_modified = os.path.getmtime(filename)``. |
| | | |
| | | The details are available in the `extracted Response documentation |
| | | <http://pythonpaste.org/webob/class-webob.Response.html>`_. |
| | | <http://docs.webob.org/en/latest/modules/webob.html#headers>`_. |
| | | |
| | | .. index:: |
| | | single: response (creating) |
| | |
| | | ``default_content_type`` you can override this behavior. |
| | | |
| | | .. index:: |
| | | single: response exceptions |
| | | single: exception responses |
| | | |
| | | Exception Responses |
| | | +++++++++++++++++++ |
| | |
| | | More details about the response object API are available in the |
| | | :mod:`pyramid.response` documentation. More details about exception |
| | | responses are in the :mod:`pyramid.httpexceptions` API documentation. The |
| | | `WebOb documentation <http://pythonpaste.org/webob>`_ is also useful. |
| | | `WebOb documentation <http://docs.webob.org/en/latest/index.html>`_ is also |
| | | useful. |
| | | |
| | |
| | | globalreg = getGlobalSiteManager() |
| | | config = Configurator(registry=globalreg) |
| | | config.setup_registry(settings=settings) |
| | | config.hook_zca() |
| | | config.include('some.other.application') |
| | | return config.make_wsgi_app() |
| | | |
New file |
| | |
| | | make clean html SPHINXBUILD=../env26/bin/sphinx-build |
| | |
| | | # play badly with C extensions. |
| | | WSGIApplicationGroup %{GLOBAL} |
| | | WSGIPassAuthorization On |
| | | WSGIDaemonProcess pyramid user=chrism group=staff processes=1 \ |
| | | threads=4 \ |
| | | WSGIDaemonProcess pyramid user=chrism group=staff threads=4 \ |
| | | python-path=/Users/chrism/modwsgi/env/lib/python2.6/site-packages |
| | | WSGIScriptAlias /myapp /Users/chrism/modwsgi/env/pyramid.wsgi |
| | | |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [server:main] |
| | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.zodbconn', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'repoze.retry', |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'ZODB3', |
| | | 'WebError', |
| | | 'docutils', |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [server:main] |
| | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.zodbconn', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'repoze.retry', |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'ZODB3', |
| | | 'WebError', |
| | | ] |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org/">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [server:main] |
| | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.zodbconn', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'repoze.retry', |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'ZODB3', |
| | | 'WebError', |
| | | ] |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [server:main] |
| | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.zodbconn', |
| | | 'repoze.tm2>=1.0b1', |
| | | 'repoze.retry', |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'ZODB3', |
| | | 'WebError', |
| | | 'docutils', |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | tutorial |
| | | |
| | | [server:main] |
| | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.zodbconn', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'repoze.retry', |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'ZODB3', |
| | | 'WebError', |
| | | 'docutils', |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | ``models.py`` file: |
| | | |
| | | .. literalinclude:: src/authorization/tutorial/models.py |
| | | :lines: 3-4,45-49 |
| | | :lines: 3-4,45-50 |
| | | :linenos: |
| | | :language: python |
| | | |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | return dict(page = context, |
| | | return dict(page = page, |
| | | content = content, |
| | | logged_in = logged_in, |
| | | edit_url = edit_url) |
| | |
| | | ``settings`` is passed to the Configurator as a keyword argument with the |
| | | dictionary values passed by PasteDeploy as the ``**settings`` argument. This |
| | | will be a dictionary of settings parsed from the ``.ini`` file, which |
| | | contains deployment-related values such as ``reload_templates``, |
| | | contains deployment-related values such as ``pyramid.reload_templates``, |
| | | ``db_string``, etc. |
| | | |
| | | We now can call :meth:`pyramid.config.Configurator.add_static_view` with the |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [pipeline:main] |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [filter:weberror] |
| | |
| | | transaction.commit() |
| | | except IntegrityError: |
| | | # already created |
| | | pass |
| | | transaction.abort() |
| | | |
| | | class RootFactory(object): |
| | | __acl__ = [ (Allow, Everyone, 'view'), |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [pipeline:main] |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [filter:weberror] |
| | |
| | | try: |
| | | populate() |
| | | except IntegrityError: |
| | | pass |
| | | transaction.abort() |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [pipeline:main] |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [filter:weberror] |
| | |
| | | transaction.commit() |
| | | except IntegrityError: |
| | | # already created |
| | | pass |
| | | transaction.abort() |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [pipeline:main] |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [filter:weberror] |
| | |
| | | transaction.commit() |
| | | except IntegrityError: |
| | | # already created |
| | | pass |
| | | transaction.abort() |
| | | |
| | | class RootFactory(object): |
| | | __acl__ = [ (Allow, Everyone, 'view'), |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [pipeline:main] |
| | |
| | | [app:tutorial] |
| | | use = egg:tutorial |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | sqlalchemy.url = sqlite:///%(here)s/tutorial.db |
| | | |
| | | [filter:weberror] |
| | |
| | | transaction.commit() |
| | | except IntegrityError: |
| | | # already created |
| | | pass |
| | | transaction.abort() |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | body h3, |
| | | body h4, |
| | | body h5, |
| | | body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;} |
| | | #wrap{min-height:100%;} |
| | | #header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;} |
| | | #header{background:#000000;top:0;font-size:14px;} |
| | |
| | | <meta name="keywords" content="python web application" /> |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&subset=latin" type="text/css" media="screen" charset="utf-8" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | However, you won't have to do much to use your existing BFG applications on |
| | | Pyramid. There's automation which will change most of your import statements |
| | | and ZCML declarations. See |
| | | http://docs.pylonshq.com/pyramid/dev/tutorials/bfg/index.html for upgrade |
| | | instructions. |
| | | http://docs.pylonsproject.org/projects/pyramid/current/tutorials/bfg/index.html |
| | | for upgrade instructions. |
| | | |
| | | Pylons 1 users will need to do more work to use Pyramid, as Pyramid shares no |
| | | "DNA" with Pylons. It is hoped that over time documentation and upgrade code |
| | |
| | | |
| | | - Default HTTP exception view. |
| | | |
| | | - ``http_cache`` view configuration parameter causes Pyramid to set HTTP |
| | | caching headers. |
| | | |
| | | - Features that make it easier to write scripts that work in a :app:`Pyramid` |
| | | environment. |
| | | |
| | | ``request.response`` |
| | | ~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | |
| | | exception to that of Pyramid 1.0 (the exception will propagate to |
| | | middleware and to the WSGI server). |
| | | |
| | | ``http_cache`` |
| | | ~~~~~~~~~~~~~~ |
| | | |
| | | A new value ``http_cache`` can be used as a :term:`view configuration` |
| | | parameter. |
| | | |
| | | When you supply an ``http_cache`` value to a view configuration, the |
| | | ``Expires`` and ``Cache-Control`` headers of a response generated by the |
| | | associated view callable are modified. The value for ``http_cache`` may be |
| | | one of the following: |
| | | |
| | | - A nonzero integer. If it's a nonzero integer, it's treated as a number |
| | | of seconds. This number of seconds will be used to compute the |
| | | ``Expires`` header and the ``Cache-Control: max-age`` parameter of |
| | | responses to requests which call this view. For example: |
| | | ``http_cache=3600`` instructs the requesting browser to 'cache this |
| | | response for an hour, please'. |
| | | |
| | | - A ``datetime.timedelta`` instance. If it's a ``datetime.timedelta`` |
| | | instance, it will be converted into a number of seconds, and that number |
| | | of seconds will be used to compute the ``Expires`` header and the |
| | | ``Cache-Control: max-age`` parameter of responses to requests which call |
| | | this view. For example: ``http_cache=datetime.timedelta(days=1)`` |
| | | instructs the requesting browser to 'cache this response for a day, |
| | | please'. |
| | | |
| | | - Zero (``0``). If the value is zero, the ``Cache-Control`` and |
| | | ``Expires`` headers present in all responses from this view will be |
| | | composed such that client browser cache (and any intermediate caches) are |
| | | instructed to never cache the response. |
| | | |
| | | - A two-tuple. If it's a two tuple (e.g. ``http_cache=(1, |
| | | {'public':True})``), the first value in the tuple may be a nonzero |
| | | integer or a ``datetime.timedelta`` instance; in either case this value |
| | | will be used as the number of seconds to cache the response. The second |
| | | value in the tuple must be a dictionary. The values present in the |
| | | dictionary will be used as input to the ``Cache-Control`` response |
| | | header. For example: ``http_cache=(3600, {'public':True})`` means 'cache |
| | | for an hour, and add ``public`` to the Cache-Control header of the |
| | | response'. All keys and values supported by the |
| | | ``webob.cachecontrol.CacheControl`` interface may be added to the |
| | | dictionary. Supplying ``{'public':True}`` is equivalent to calling |
| | | ``response.cache_control.public = True``. |
| | | |
| | | Providing a non-tuple value as ``http_cache`` is equivalent to calling |
| | | ``response.cache_expires(value)`` within your view's body. |
| | | |
| | | Providing a two-tuple value as ``http_cache`` is equivalent to calling |
| | | ``response.cache_expires(value[0], **value[1])`` within your view's body. |
| | | |
| | | If you wish to avoid influencing, the ``Expires`` header, and instead wish |
| | | to only influence ``Cache-Control`` headers, pass a tuple as ``http_cache`` |
| | | with the first element of ``None``, e.g.: ``(None, {'public':True})``. |
| | | |
| | | The environment setting ``PYRAMID_PREVENT_HTTP_CACHE`` and configuration |
| | | file value ``prevent_http_cache`` are synonymous and allow you to prevent |
| | | HTTP cache headers from being set by Pyramid's ``http_cache`` machinery |
| | | globally in a process. see :ref:`influencing_http_caching` and |
| | | :ref:`preventing_http_caching`. |
| | | |
| | | Easier Scripting Writing |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | A new API function :func:`pyramid.paster.bootstrap` has been added to make |
| | | writing scripts that need to work under Pyramid environment easier, e.g.: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.paster import bootstrap |
| | | info = bootstrap('/path/to/my/development.ini') |
| | | request = info['request'] |
| | | print request.route_url('myroute') |
| | | |
| | | See :ref:`writing_a_script` for more details. |
| | | |
| | | Minor Feature Additions |
| | | ----------------------- |
| | | |
| | | - New request attribute: ``json``. If the request's ``content_type`` is |
| | | ``application/json``, this attribute will contain the JSON-decoded |
| | | variant of the request body. If the request's ``content_type`` is not |
| | | ``application/json``, this attribute will be ``None``. |
| | | - It is now possible to invoke ``paster pshell`` even if the paste ini file |
| | | section name pointed to in its argument is not actually a Pyramid WSGI |
| | | application. The shell will work in a degraded mode, and will warn the |
| | | user. See "The Interactive Shell" in the "Creating a Pyramid Project" |
| | | narrative documentation section. |
| | | |
| | | - A new value ``http_cache`` can be used as a :term:`view configuration` |
| | | parameter. |
| | | - The ``paster pshell``, ``paster pviews``, and ``paster proutes`` commands |
| | | each now under the hood uses :func:`pyramid.paster.bootstrap`, which makes |
| | | it possible to supply an ``.ini`` file without naming the "right" section |
| | | in the file that points at the actual Pyramid application. Instead, you |
| | | can generally just run ``paster {pshell|proutes|pviews} development.ini`` |
| | | and it will do mostly the right thing. |
| | | |
| | | When you supply an ``http_cache`` value to a view configuration, the |
| | | ``Expires`` and ``Cache-Control`` headers of a response generated by the |
| | | associated view callable are modified. The value for ``http_cache`` may be |
| | | one of the following: |
| | | - It is now possible to add a ``[pshell]`` section to your application's .ini |
| | | configuration file, which influences the global names available to a pshell |
| | | session. See :ref:`extending_pshell`. |
| | | |
| | | - A nonzero integer. If it's a nonzero integer, it's treated as a number |
| | | of seconds. This number of seconds will be used to compute the |
| | | ``Expires`` header and the ``Cache-Control: max-age`` parameter of |
| | | responses to requests which call this view. For example: |
| | | ``http_cache=3600`` instructs the requesting browser to 'cache this |
| | | response for an hour, please'. |
| | | - The :meth:`pyramid.config.Configurator.scan` method has grown a ``**kw`` |
| | | argument. ``kw`` argument represents a set of keyword arguments to pass to |
| | | the Venusian ``Scanner`` object created by Pyramid. (See the |
| | | :term:`Venusian` documentation for more information about ``Scanner``). |
| | | |
| | | - A ``datetime.timedelta`` instance. If it's a ``datetime.timedelta`` |
| | | instance, it will be converted into a number of seconds, and that number |
| | | of seconds will be used to compute the ``Expires`` header and the |
| | | ``Cache-Control: max-age`` parameter of responses to requests which call |
| | | this view. For example: ``http_cache=datetime.timedelta(days=1)`` |
| | | instructs the requesting browser to 'cache this response for a day, |
| | | please'. |
| | | |
| | | - Zero (``0``). If the value is zero, the ``Cache-Control`` and |
| | | ``Expires`` headers present in all responses from this view will be |
| | | composed such that client browser cache (and any intermediate caches) are |
| | | instructed to never cache the response. |
| | | |
| | | - A two-tuple. If it's a two tuple (e.g. ``http_cache=(1, |
| | | {'public':True})``), the first value in the tuple may be a nonzero |
| | | integer or a ``datetime.timedelta`` instance; in either case this value |
| | | will be used as the number of seconds to cache the response. The second |
| | | value in the tuple must be a dictionary. The values present in the |
| | | dictionary will be used as input to the ``Cache-Control`` response |
| | | header. For example: ``http_cache=(3600, {'public':True})`` means 'cache |
| | | for an hour, and add ``public`` to the Cache-Control header of the |
| | | response'. All keys and values supported by the |
| | | ``webob.cachecontrol.CacheControl`` interface may be added to the |
| | | dictionary. Supplying ``{'public':True}`` is equivalent to calling |
| | | ``response.cache_control.public = True``. |
| | | |
| | | Providing a non-tuple value as ``http_cache`` is equivalent to calling |
| | | ``response.cache_expires(value)`` within your view's body. |
| | | |
| | | Providing a two-tuple value as ``http_cache`` is equivalent to calling |
| | | ``response.cache_expires(value[0], **value[1])`` within your view's body. |
| | | |
| | | If you wish to avoid influencing, the ``Expires`` header, and instead wish |
| | | to only influence ``Cache-Control`` headers, pass a tuple as ``http_cache`` |
| | | with the first element of ``None``, e.g.: ``(None, {'public':True})``. |
| | | - New request property: ``json_body``. This property will return the |
| | | JSON-decoded variant of the request body. If the request body is not |
| | | well-formed JSON, this property will raise an exception. |
| | | |
| | | - A `JSONP <http://en.wikipedia.org/wiki/JSONP>`_ renderer. See |
| | | :ref:`jsonp_renderer` for more details. |
| | |
| | | preprocessor to be specified as a Python callable or Python dotted name. |
| | | See https://github.com/Pylons/pyramid/pull/183 for rationale. |
| | | |
| | | - New API class: :class:`pyramid.static.static_view`. This supersedes the |
| | | (now deprecated) :class:`pyramid.view.static` class. |
| | | :class:`pyramid.static.static_view`, by default, serves up documents as the |
| | | result of the request's ``path_info``, attribute rather than it's |
| | | ``subpath`` attribute (the inverse was true of |
| | | :class:`pyramid.view.static`, and still is). |
| | | :class:`pyramid.static.static_view` exposes a ``use_subpath`` flag for use |
| | | when you want the static view to behave like the older deprecated version. |
| | | |
| | | - A new api function :func:`pyramid.scripting.prepare` has been added. It is |
| | | a lower-level analogue of :func:`pyramid.paster.boostrap` that accepts a |
| | | request and a registry instead of a config file argument, and is used for |
| | | the same purpose: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.scripting import prepare |
| | | info = prepare(registry=myregistry) |
| | | request = info['request'] |
| | | print request.route_url('myroute') |
| | | |
| | | - A new API function :func:`pyramid.scripting.make_request` has been added. |
| | | The resulting request will have a ``registry`` attribute. It is meant to |
| | | be used in conjunction with :func:`pyramid.scripting.prepare` and/or |
| | | :func:`pyramid.paster.bootstrap` (both of which accept a request as an |
| | | argument): |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.scripting import make_request |
| | | request = make_request('/') |
| | | |
| | | - New API attribute :attr:`pyramid.config.global_registries` is an iterable |
| | | object that contains references to every Pyramid registry loaded into the |
| | | current process via :meth:`pyramid.config.Configurator.make_app`. It also |
| | | has a ``last`` attribute containing the last registry loaded. This is used |
| | | by the scripting machinery, and is available for introspection. |
| | | |
| | | - Added the :attr:`pyramid.renderers.null_renderer` object as an API. The |
| | | null renderer is an object that can be used in advanced integration cases |
| | | as input to the view configuration ``renderer=`` argument. When the null |
| | | renderer is used as a view renderer argument, Pyramid avoids converting the |
| | | view callable result into a Response object. This is useful if you want to |
| | | reuse the view configuration and lookup machinery outside the context of |
| | | its use by the Pyramid router. (This feature was added for consumption by |
| | | the ``pyramid_rpc`` package, which uses view configuration and lookup |
| | | outside the context of a router in exactly this way.) |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | |
| | | |
| | | Deprecations and Behavior Differences |
| | | ------------------------------------- |
| | | |
| | | .. note:: Under Python 2.7+, it's necessary to pass the Python interpreter |
| | | the correct warning flags to see deprecation warnings emitted by Pyramid |
| | | when porting your application from an older version of Pyramid. Use the |
| | | ``PYTHONWARNINGS`` environment variable with the value ``all`` in the |
| | | shell you use to invoke ``paster serve`` to see these warnings, e.g. on |
| | | UNIX, ``PYTHONWARNINGS=all bin/paster serve development.ini``. Python 2.5 |
| | | and 2.6 show deprecation warnings by default, so this is unecessary there. |
| | | All deprecation warnings are emitted to the console. |
| | | |
| | | - The :class:`pyramid.view.static` class has been deprecated in favor of the |
| | | newer :class:`pyramid.static.static_view` class. A deprecation warning is |
| | | raised when it is used. You should replace it with a reference to |
| | | :class:`pyramid.static.static_view` with the ``use_subpath=True`` argument. |
| | | |
| | | - The ``paster pshell``, ``paster proutes``, and ``paster pviews`` commands |
| | | now take a single argument in the form ``/path/to/config.ini#sectionname`` |
| | | rather than the previous 2-argument spelling ``/path/to/config.ini |
| | | sectionname``. ``#sectionname`` may be omitted, in which case ``#main`` is |
| | | assumed. |
| | | |
| | | - The default Mako renderer is now configured to escape all HTML in |
| | | expression tags. This is intended to help prevent XSS attacks caused by |
| | |
| | | these methods will be removed entirely. |
| | | |
| | | - A custom request factory is now required to return a request object that |
| | | has a ``response`` attribute (or "reified"/lazy property) if they the |
| | | has a ``response`` attribute (or "reified"/lazy property) if the |
| | | request is meant to be used in a view that uses a renderer. This |
| | | ``response`` attribute should be an instance of the class |
| | | :class:`pyramid.response.Response`. |
| | |
| | | - Deprecated the |
| | | :meth:`pyramid.config.Configurator.set_renderer_globals_factory` method and |
| | | the ``renderer_globals`` Configurator constructor parameter. Users should |
| | | use convert code using this feature to use a BeforeRender event als |
| | | :ref:`beforerender_event`. |
| | | convert code using this feature to use a BeforeRender event. See the section |
| | | :ref:`beforerender_event` in the Hooks chapter. |
| | | |
| | | - In Pyramid 1.0, the :class:`pyramid.events.subscriber` directive behaved |
| | | contrary to the documentation when passed more than one interface object to |
| | |
| | | def expects_object_event(object, event): |
| | | print object, event |
| | | |
| | | - In 1.0, if a :class:`pyramid.events.BeforeRender` event subscriber added a |
| | | value via the ``__setitem__`` or ``update`` methods of the event object |
| | | with a key that already existed in the renderer globals dictionary, a |
| | | ``KeyError`` was raised. With the deprecation of the |
| | | "add_renderer_globals" feature of the configurator, there was no way to |
| | | override an existing value in the renderer globals dictionary that already |
| | | existed. Now, the event object will overwrite an older value that is |
| | | already in the globals dictionary when its ``__setitem__`` or ``update`` is |
| | | called (as well as the new ``setdefault`` method), just like a plain old |
| | | dictionary. As a result, for maximum interoperability with other |
| | | third-party subscribers, if you write an event subscriber meant to be used |
| | | as a BeforeRender subscriber, your subscriber code will now need to (using |
| | | ``.get`` or ``__contains__`` of the event object) ensure no value already |
| | | exists in the renderer globals dictionary before setting an overriding |
| | | value. |
| | | |
| | | - The :meth:`pyramid.config.Configurator.add_route` method allowed two routes |
| | | with the same route to be added without an intermediate call to |
| | | :meth:`pyramid.config.Configurator.commit`. If you now receive a |
| | | ``ConfigurationError`` at startup time that appears to be ``add_route`` |
| | | related, you'll need to either a) ensure that all of your route names are |
| | | unique or b) call ``config.commit()`` before adding a second route with the |
| | | name of a previously added name or c) use a Configurator that works in |
| | | ``autocommit`` mode. |
| | | |
| | | Dependency Changes |
| | | ------------------ |
| | | |
| | |
| | | Documentation Enhancements |
| | | -------------------------- |
| | | |
| | | - Added a section entitled :ref:`writing_a_script` to the "Command-Line |
| | | Pyramid" chapter. |
| | | |
| | | - The :ref:`bfg_wiki_tutorial` was updated slightly. |
| | | |
| | | - The :ref:`bfg_sql_wiki_tutorial` was updated slightly. |
New file |
| | |
| | | try: |
| | | import json |
| | | except ImportError: # pragma: no cover |
| | | try: |
| | | import simplejson as json |
| | | except NotImplementedError: |
| | | from django.utils import simplejson as json # GAE |
| | | |
| | |
| | | import inspect |
| | | import logging |
| | | import os |
| | | import re |
| | | import sys |
| | | import types |
| | | import traceback |
| | | import warnings |
| | | from hashlib import md5 |
| | | |
| | | import venusian |
| | | |
| | |
| | | from pyramid.interfaces import IRendererGlobalsFactory |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IRequestFactory |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.interfaces import IResponse |
| | | from pyramid.interfaces import IRootFactory |
| | | from pyramid.interfaces import IRouteRequest |
| | |
| | | |
| | | from pyramid import renderers |
| | | from pyramid.authorization import ACLAuthorizationPolicy |
| | | from pyramid.compat import all |
| | | from pyramid.compat import md5 |
| | | from pyramid.compat import any |
| | | from pyramid.events import ApplicationCreated |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.exceptions import PredicateMismatch |
| | |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.i18n import get_localizer |
| | | from pyramid.log import make_stream_logger |
| | | from pyramid.mako_templating import renderer_factory as mako_renderer_factory |
| | | from pyramid.path import caller_package |
| | | from pyramid.path import package_path |
| | |
| | | from pyramid.request import route_request_iface |
| | | from pyramid.asset import PackageOverrides |
| | | from pyramid.asset import resolve_asset_spec |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | from pyramid.settings import Settings |
| | | from pyramid.static import StaticURLInfo |
| | | from pyramid.threadlocal import get_current_registry |
| | |
| | | from pyramid.traversal import DefaultRootFactory |
| | | from pyramid.traversal import find_interface |
| | | from pyramid.traversal import traversal_path |
| | | from pyramid.tweens import excview_tween_factory |
| | | from pyramid.tweens import Tweens |
| | | from pyramid.tweens import tween_factory_name |
| | | from pyramid.tweens import MAIN, INGRESS, EXCVIEW |
| | | from pyramid.urldispatch import RoutesMapper |
| | | from pyramid.util import DottedNameResolver |
| | | from pyramid.util import WeakOrderedSet |
| | | from pyramid.view import render_view_to_response |
| | | |
| | | DEFAULT_RENDERERS = ( |
| | |
| | | |
| | | The Configurator accepts a number of arguments: ``registry``, |
| | | ``package``, ``settings``, ``root_factory``, ``authentication_policy``, |
| | | ``authorization_policy``, ``renderers`` ``debug_logger``, |
| | | ``authorization_policy``, ``renderers``, ``debug_logger``, |
| | | ``locale_negotiator``, ``request_factory``, ``renderer_globals_factory``, |
| | | ``default_permission``, ``session_factory``, ``default_view_mapper``, |
| | | ``autocommit``, and ``exceptionresponse_view``. |
| | |
| | | :meth:`pyramid.config.Configurator.add_renderer`). If |
| | | it is not passed, a default set of renderer factories is used. |
| | | |
| | | If ``debug_logger`` is not passed, a default debug logger that |
| | | logs to stderr will be used. If it is passed, it should be an |
| | | instance of the :class:`logging.Logger` (PEP 282) standard library |
| | | class or a :term:`dotted Python name` to same. The debug logger |
| | | is used by :app:`Pyramid` itself to log warnings and |
| | | authorization debugging information. |
| | | If ``debug_logger`` is not passed, a default debug logger that logs to a |
| | | logger will be used (the logger name will be the package name of the |
| | | *caller* of this configurator). If it is passed, it should be an |
| | | instance of the :class:`logging.Logger` (PEP 282) standard library class |
| | | or a Python logger name. The debug logger is used by :app:`Pyramid` |
| | | itself to log warnings and authorization debugging information. |
| | | |
| | | If ``locale_negotiator`` is passed, it should be a :term:`locale |
| | | negotiator` implementation or a :term:`dotted Python name` to |
| | |
| | | :meth:`pyramid.config.Configuration.commit` is called (or executed |
| | | immediately if ``autocommit`` is ``True``). |
| | | |
| | | .. note:: This method is typically only used by :app:`Pyramid` |
| | | .. warning:: This method is typically only used by :app:`Pyramid` |
| | | framework extension authors, not by :app:`Pyramid` application |
| | | developers. |
| | | |
| | |
| | | """ |
| | | Add a directive method to the configurator. |
| | | |
| | | .. warning:: This method is typically only used by :app:`Pyramid` |
| | | framework extension authors, not by :app:`Pyramid` application |
| | | developers. |
| | | |
| | | Framework extenders can add directive methods to a configurator by |
| | | instructing their users to call ``config.add_directive('somename', |
| | | 'some.callable')``. This will make ``some.callable`` accessible as |
| | |
| | | """ Return a new Configurator instance with the same registry |
| | | as this configurator using the package supplied as the |
| | | ``package`` argument to the new configurator. ``package`` may |
| | | be an actual Python package object or a Python dotted name |
| | | be an actual Python package object or a :term:`dotted Python name` |
| | | representing a package.""" |
| | | context = self._ctx |
| | | if context is None: |
| | |
| | | policies, renderers, a debug logger, a locale negotiator, and various |
| | | other settings using the configurator's current registry, as per the |
| | | descriptions in the Configurator constructor.""" |
| | | tweens = [] |
| | | includes = [] |
| | | if settings: |
| | | includes = [x.strip() for x in |
| | | settings.get('pyramid.include', '').splitlines()] |
| | | tweens = [x.strip() for x in |
| | | settings.get('pyramid.tweens','').splitlines()] |
| | | registry = self.registry |
| | | self._fix_registry() |
| | | self._set_settings(settings) |
| | |
| | | # cope with WebOb exc objects not decoratored with IExceptionResponse |
| | | from webob.exc import WSGIHTTPException as WebobWSGIHTTPException |
| | | registry.registerSelfAdapter((WebobResponse,), IResponse) |
| | | debug_logger = self.maybe_dotted(debug_logger) |
| | | |
| | | if debug_logger is None: |
| | | debug_logger = make_stream_logger('pyramid.debug', sys.stderr) |
| | | debug_logger = logging.getLogger(self.package_name) |
| | | elif isinstance(debug_logger, basestring): |
| | | debug_logger = logging.getLogger(debug_logger) |
| | | |
| | | registry.registerUtility(debug_logger, IDebugLogger) |
| | | if authentication_policy or authorization_policy: |
| | | self._set_security_policies(authentication_policy, |
| | |
| | | if default_view_mapper is not None: |
| | | self.set_view_mapper(default_view_mapper) |
| | | self.commit() |
| | | for inc in includes: |
| | | self.include(inc) |
| | | for factory in tweens: |
| | | self._add_tween(factory, explicit=True) |
| | | |
| | | def hook_zca(self): |
| | | """ Call :func:`zope.component.getSiteManager.sethook` with |
| | |
| | | |
| | | def derive_view(self, view, attr=None, renderer=None): |
| | | """ |
| | | |
| | | Create a :term:`view callable` using the function, instance, |
| | | or class (or :term:`dotted Python name` referring to the same) |
| | | provided as ``view`` object. |
| | | |
| | | .. warning:: This method is typically only used by :app:`Pyramid` |
| | | framework extension authors, not by :app:`Pyramid` application |
| | | developers. |
| | | |
| | | This is API is useful to framework extenders who create |
| | | pluggable systems which need to register 'proxy' view |
| | |
| | | :term:`response` object. """ |
| | | return self._derive_view(view, attr=attr, renderer=renderer) |
| | | |
| | | @action_method |
| | | def add_tween(self, tween_factory, alias=None, under=None, over=None): |
| | | """ |
| | | Add a 'tween factory'. A :term:`tween` (a contraction of 'between') |
| | | is a bit of code that sits between the Pyramid router's main request |
| | | handling function and the upstream WSGI component that uses |
| | | :app:`Pyramid` as its 'app'. This is a feature that may be used by |
| | | Pyramid framework extensions, to provide, for example, |
| | | Pyramid-specific view timing support, bookkeeping code that examines |
| | | exceptions before they are returned to the upstream WSGI application, |
| | | or a variety of other features. Tweens behave a bit like |
| | | :term:`WSGI` 'middleware' but they have the benefit of running in a |
| | | context in which they have access to the Pyramid :term:`application |
| | | registry` as well as the Pyramid rendering machinery. |
| | | |
| | | .. note:: You can view the tween ordering configured into a given |
| | | Pyramid application by using the ``paster ptweens`` |
| | | command. See :ref:`displaying_tweens`. |
| | | |
| | | The ``alias`` argument, if it is not ``None``, should be a string. |
| | | The string will represent a value that other callers of ``add_tween`` |
| | | may pass as an ``under`` and ``over`` argument instead of a dotted |
| | | name to a tween factory. |
| | | |
| | | The ``under`` and ``over`` arguments allow the caller of |
| | | ``add_tween`` to provide a hint about where in the tween chain this |
| | | tween factory should be placed when an implicit tween chain is used. |
| | | These hints are only used used when an explicit tween chain is not |
| | | used (when the ``pyramid.tweens`` configuration value is not set). |
| | | Allowable values for ``under`` or ``over`` (or both) are: |
| | | |
| | | - ``None`` (the default). |
| | | |
| | | - A :term:`dotted Python name` to a tween factory: a string |
| | | representing the predicted dotted name of a tween factory added in |
| | | a call to ``add_tween`` in the same configuration session. |
| | | |
| | | - A tween alias: a string representing the predicted value of |
| | | ``alias`` in a separate call to ``add_tween`` in the same |
| | | configuration session |
| | | |
| | | - One of the constants :attr:`pyramid.tweens.MAIN`, |
| | | :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. |
| | | |
| | | ``under`` means 'closer to the main Pyramid application than', |
| | | ``over`` means 'closer to the request ingress than'. |
| | | |
| | | For example, calling ``add_tween(factory, over=pyramid.tweens.MAIN)`` |
| | | will attempt to place the tween factory represented by ``factory`` |
| | | directly 'above' (in ``paster ptweens`` order) the main Pyramid |
| | | request handler. Likewise, calling ``add_tween(factory, |
| | | over=pyramid.tweens.MAIN, under='someothertween')`` will attempt to |
| | | place this tween factory 'above' the main handler but 'below' (a |
| | | fictional) 'someothertween' tween factory (which was presumably added |
| | | via ``add_tween(factory, alias='someothertween')``). |
| | | |
| | | If an ``under`` or ``over`` value is provided that does not match a |
| | | tween factory dotted name or alias in the current configuration, that |
| | | value will be ignored. It is not an error to provide an ``under`` or |
| | | ``over`` value that matches an unused tween factory. |
| | | |
| | | Specifying neither ``over`` nor ``under`` is equivalent to specifying |
| | | ``under=INGRESS``. |
| | | |
| | | Implicit tween ordering is obviously only best-effort. Pyramid will |
| | | attempt to present an implicit order of tweens as best it can, but |
| | | the only surefire way to get any particular ordering is to use an |
| | | explicit tween order. A user may always override the implicit tween |
| | | ordering by using an explicit ``pyramid.tweens`` configuration value |
| | | setting. |
| | | |
| | | ``alias``, ``under``, and ``over`` arguments are ignored when an |
| | | explicit tween chain is specified using the ``pyramid.tweens`` |
| | | configuration value. |
| | | |
| | | For more information, see :ref:`registering_tweens`. |
| | | |
| | | .. note:: This feature is new as of Pyramid 1.1.1. |
| | | """ |
| | | return self._add_tween(tween_factory, alias=alias, under=under, |
| | | over=over, explicit=False) |
| | | |
| | | def _add_tween(self, tween_factory, alias=None, under=None, over=None, |
| | | explicit=False): |
| | | tween_factory = self.maybe_dotted(tween_factory) |
| | | name = tween_factory_name(tween_factory) |
| | | if alias in (MAIN, INGRESS): |
| | | raise ConfigurationError('%s is a reserved tween name' % alias) |
| | | |
| | | if over is INGRESS: |
| | | raise ConfigurationError('%s cannot be over INGRESS' % name) |
| | | |
| | | if under is MAIN: |
| | | raise ConfigurationError('%s cannot be under MAIN' % name) |
| | | |
| | | registry = self.registry |
| | | tweens = registry.queryUtility(ITweens) |
| | | if tweens is None: |
| | | tweens = Tweens() |
| | | registry.registerUtility(tweens, ITweens) |
| | | tweens.add_implicit(tween_factory_name(excview_tween_factory), |
| | | excview_tween_factory, alias=EXCVIEW, |
| | | over=MAIN) |
| | | if explicit: |
| | | tweens.add_explicit(name, tween_factory) |
| | | else: |
| | | tweens.add_implicit(name, tween_factory, alias=alias, under=under, |
| | | over=over) |
| | | self.action(('tween', name, explicit)) |
| | | if not explicit and alias is not None: |
| | | self.action(('tween', alias, explicit)) |
| | | |
| | | @action_method |
| | | def add_request_handler(self, factory, name): # pragma: no cover |
| | | # XXX bw compat for debugtoolbar |
| | | return self._add_tween(factory, explicit=False) |
| | | |
| | | @action_method |
| | | def add_subscriber(self, subscriber, iface=None): |
| | | """Add an event :term:`subscriber` for the event stream |
| | |
| | | def make_wsgi_app(self): |
| | | """ Commits any pending configuration statements, sends a |
| | | :class:`pyramid.events.ApplicationCreated` event to all listeners, |
| | | and returns a :app:`Pyramid` WSGI application representing the |
| | | committed configuration state.""" |
| | | adds this configuration's registry to |
| | | :attr:`pyramid.config.global_registries`, and returns a |
| | | :app:`Pyramid` WSGI application representing the committed |
| | | configuration state.""" |
| | | self.commit() |
| | | from pyramid.router import Router # avoid circdep |
| | | app = Router(self.registry) |
| | | global_registries.add(self.registry) |
| | | # We push the registry on to the stack here in case any code |
| | | # that depends on the registry threadlocal APIs used in |
| | | # listeners subscribed to the IApplicationCreated event. |
| | |
| | | self.registry.notify(ApplicationCreated(app)) |
| | | finally: |
| | | self.manager.pop() |
| | | |
| | | return app |
| | | |
| | | @action_method |
| | |
| | | ``default_permission`` argument, or if |
| | | :meth:`pyramid.config.Configurator.set_default_permission` |
| | | was used prior to this view registration. Pass the string |
| | | ``__no_permission_required__`` as the permission argument to |
| | | explicitly indicate that the view should always be |
| | | executable by entirely anonymous users, regardless of the |
| | | default permission, bypassing any :term:`authorization |
| | | :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the |
| | | permission argument to explicitly indicate that the view should |
| | | always be executable by entirely anonymous users, regardless of |
| | | the default permission, bypassing any :term:`authorization |
| | | policy` that may be in effect. |
| | | |
| | | attr |
| | |
| | | |
| | | http_cache |
| | | |
| | | .. note:: This feature is new as of Pyramid 1.1. |
| | | |
| | | When you supply an ``http_cache`` value to a view configuration, |
| | | the ``Expires`` and ``Cache-Control`` headers of a response |
| | | generated by the associated view callable are modified. The value |
| | |
| | | instead wish to only influence ``Cache-Control`` headers, pass a |
| | | tuple as ``http_cache`` with the first element of ``None``, e.g.: |
| | | ``(None, {'public':True})``. |
| | | |
| | | If you wish to prevent a view that uses ``http_cache`` in its |
| | | configuration from having its caching response headers changed by |
| | | this machinery, set ``response.cache_control.prevent_auto = True`` |
| | | before returning the response from the view. This effectively |
| | | disables any HTTP caching done by ``http_cache`` for that response. |
| | | |
| | | wrapper |
| | | |
| | |
| | | |
| | | This value must match the ``name`` of a :term:`route |
| | | configuration` declaration (see :ref:`urldispatch_chapter`) |
| | | that must match before this view will be called. Note that |
| | | the ``route`` configuration referred to by ``route_name`` |
| | | usually has a ``*traverse`` token in the value of its |
| | | ``path``, representing a part of the path that will be used |
| | | by :term:`traversal` against the result of the route's |
| | | :term:`root factory`. |
| | | |
| | | .. warning:: Using this argument services an advanced |
| | | feature that isn't often used unless you want to perform |
| | | traversal *after* a route has matched. See |
| | | :ref:`hybrid_chapter` for more information on using this |
| | | advanced feature. |
| | | that must match before this view will be called. |
| | | |
| | | request_type |
| | | |
| | |
| | | should only be used to support older code bases which depend upon |
| | | them.* Use a separate call to |
| | | :meth:`pyramid.config.Configurator.add_view` to associate a view |
| | | with a route. See :ref:`add_route_view_config` for more info. |
| | | with a route using the ``route_name`` argument. |
| | | |
| | | view |
| | | |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1; see |
| | | :ref:`add_route_view_config`. |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1. |
| | | |
| | | A Python object or :term:`dotted Python name` to the same |
| | | object that will be used as a view callable when this route |
| | |
| | | |
| | | view_context |
| | | |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1; see |
| | | :ref:`add_route_view_config`. |
| | | |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1. |
| | | |
| | | A class or an :term:`interface` or :term:`dotted Python |
| | | name` to the same object which the :term:`context` of the |
| | | view should match for the view named by the route to be |
| | |
| | | |
| | | view_permission |
| | | |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1; see |
| | | :ref:`add_route_view_config`. |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1. |
| | | |
| | | The permission name required to invoke the view associated |
| | | with this route. e.g. ``edit``. (see |
| | |
| | | |
| | | view_renderer |
| | | |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1; see |
| | | :ref:`add_route_view_config`. |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1. |
| | | |
| | | This is either a single string term (e.g. ``json``) or a |
| | | string implying a path or :term:`asset specification` |
| | |
| | | |
| | | view_attr |
| | | |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1; see |
| | | :ref:`add_route_view_config`. |
| | | .. warning:: Deprecated as of :app:`Pyramid` 1.1. |
| | | |
| | | The view machinery defaults to using the ``__call__`` method |
| | | of the view callable (or the function itself, if the view |
| | |
| | | if self.route_prefix: |
| | | pattern = self.route_prefix.rstrip('/') + '/' + pattern.lstrip('/') |
| | | |
| | | discriminator = ['route', name, xhr, request_method, path_info, |
| | | request_param, header, accept] |
| | | discriminator.extend(sorted(custom_predicates)) |
| | | discriminator = tuple(discriminator) |
| | | |
| | | discriminator = ('route', name) |
| | | self.action(discriminator, None) |
| | | |
| | | return mapper.connect(name, pattern, factory, predicates=predicates, |
| | |
| | | return mapper |
| | | |
| | | # this is *not* an action method (uses caller_package) |
| | | def scan(self, package=None, categories=None): |
| | | def scan(self, package=None, categories=None, **kw): |
| | | """Scan a Python package and any of its subpackages for objects |
| | | marked with :term:`configuration decoration` such as |
| | | :class:`pyramid.view.view_config`. Any decorated object found will |
| | |
| | | :class:`pyramid.view.view_config`. See the :term:`Venusian` |
| | | documentation for more information about limiting a scan by using an |
| | | explicit set of categories. |
| | | |
| | | To perform a ``scan``, Pyramid creates a Venusian ``Scanner`` object. |
| | | The ``kw`` argument represents a set of keyword arguments to pass to |
| | | the Venusian ``Scanner`` object's constructor. See the |
| | | :term:`venusian` documentation (its ``Scanner`` class) for more |
| | | information about the constructor. By default, the only keyword |
| | | arguments passed to the Scanner constructor are ``{'config':self}`` |
| | | where ``self`` is this configurator object. This services the |
| | | requirement of all built-in Pyramid decorators, but extension systems |
| | | may require additional arguments. Providing this argument is not |
| | | often necessary; it's an advanced usage. |
| | | |
| | | .. note:: the ``**kw`` argument is new in Pyramid 1.1 |
| | | """ |
| | | package = self.maybe_dotted(package) |
| | | if package is None: # pragma: no cover |
| | | package = caller_package() |
| | | |
| | | scanner = self.venusian.Scanner(config=self) |
| | | scankw = {'config':self} |
| | | scankw.update(kw) |
| | | |
| | | scanner = self.venusian.Scanner(**scankw) |
| | | scanner.scan(package, categories=categories) |
| | | |
| | | @action_method |
| | |
| | | context = getattr(request, 'context', None) |
| | | return view(context, request) |
| | | return self.add_view(bwcompat_view, context=HTTPForbidden, |
| | | wrapper=wrapper) |
| | | wrapper=wrapper, renderer=renderer) |
| | | |
| | | @action_method |
| | | def set_notfound_view(self, view=None, attr=None, renderer=None, |
| | |
| | | context = getattr(request, 'context', None) |
| | | return view(context, request) |
| | | return self.add_view(bwcompat_view, context=HTTPNotFound, |
| | | wrapper=wrapper) |
| | | wrapper=wrapper, renderer=renderer) |
| | | |
| | | @action_method |
| | | def set_request_factory(self, factory): |
| | |
| | | If a default permission is in effect, view configurations meant to |
| | | create a truly anonymously accessible view (even :term:`exception |
| | | view` views) *must* use the explicit permission string |
| | | ``__no_permission_required__`` as the permission. When this string |
| | | is used as the ``permission`` for a view configuration, the default |
| | | permission is ignored, and the view is registered, making it |
| | | available to all callers regardless of their credentials. |
| | | :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission. |
| | | When this string is used as the ``permission`` for a view |
| | | configuration, the default permission is ignored, and the view is |
| | | registered, making it available to all callers regardless of their |
| | | credentials. |
| | | |
| | | See also :ref:`setting_a_default_permission`. |
| | | |
| | |
| | | |
| | | The ``permission`` keyword argument is used to specify the |
| | | :term:`permission` required by a user to execute the static view. By |
| | | default, it is the string ``__no_permission_required__``. The |
| | | ``__no_permission_required__`` string is a special sentinel which |
| | | indicates that, even if a :term:`default permission` exists for the |
| | | current application, the static view should be renderered to |
| | | default, it is the string |
| | | :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel |
| | | which indicates that, even if a :term:`default permission` exists for |
| | | the current application, the static view should be renderered to |
| | | completely anonymous users. This default value is permissive |
| | | because, in most web apps, static assets seldom need protection from |
| | | viewing. If ``permission`` is specified, the security checking will |
| | |
| | | continue |
| | | raise PredicateMismatch(self.name) |
| | | |
| | | def wraps_view(wrapped): |
| | | def wraps_view(wrapper): |
| | | def inner(self, view): |
| | | wrapped_view = wrapped(self, view) |
| | | return preserve_view_attrs(view, wrapped_view) |
| | | wrapper_view = wrapper(self, view) |
| | | return preserve_view_attrs(view, wrapper_view) |
| | | return inner |
| | | |
| | | def preserve_view_attrs(view, wrapped_view): |
| | | if wrapped_view is view: |
| | | def preserve_view_attrs(view, wrapper): |
| | | if wrapper is view: |
| | | return view |
| | | |
| | | original_view = getattr(view, '__original_view__', None) |
| | | |
| | | if original_view is None: |
| | | original_view = view |
| | | wrapped_view.__original_view__ = original_view |
| | | wrapped_view.__module__ = view.__module__ |
| | | wrapped_view.__doc__ = view.__doc__ |
| | | |
| | | wrapper.__wraps__ = view |
| | | wrapper.__original_view__ = original_view |
| | | wrapper.__module__ = view.__module__ |
| | | wrapper.__doc__ = view.__doc__ |
| | | |
| | | try: |
| | | wrapped_view.__name__ = view.__name__ |
| | | wrapper.__name__ = view.__name__ |
| | | except AttributeError: |
| | | wrapped_view.__name__ = repr(view) |
| | | try: |
| | | wrapped_view.__permitted__ = view.__permitted__ |
| | | except AttributeError: |
| | | pass |
| | | try: |
| | | wrapped_view.__call_permissive__ = view.__call_permissive__ |
| | | except AttributeError: |
| | | pass |
| | | try: |
| | | wrapped_view.__permission__ = view.__permission__ |
| | | except AttributeError: |
| | | pass |
| | | try: |
| | | wrapped_view.__predicated__ = view.__predicated__ |
| | | except AttributeError: |
| | | pass |
| | | try: |
| | | wrapped_view.__predicates__ = view.__predicates__ |
| | | except AttributeError: |
| | | pass |
| | | try: |
| | | wrapped_view.__accept__ = view.__accept__ |
| | | except AttributeError: |
| | | pass |
| | | try: |
| | | wrapped_view.__order__ = view.__order__ |
| | | except AttributeError: |
| | | pass |
| | | return wrapped_view |
| | | wrapper.__name__ = repr(view) |
| | | |
| | | # attrs that may not exist on "view", but, if so, must be attached to |
| | | # "wrapped view" |
| | | for attr in ('__permitted__', '__call_permissive__', '__permission__', |
| | | '__predicated__', '__predicates__', '__accept__', |
| | | '__order__'): |
| | | try: |
| | | setattr(wrapper, attr, getattr(view, attr)) |
| | | except AttributeError: |
| | | pass |
| | | |
| | | return wrapper |
| | | |
| | | class ViewDeriver(object): |
| | | def __init__(self, **kw): |
| | |
| | | self.authdebug_view( |
| | | self.secured_view( |
| | | self.owrapped_view( |
| | | self.decorated_view( |
| | | self.http_cached_view( |
| | | self.http_cached_view( |
| | | self.decorated_view( |
| | | self.rendered_view( |
| | | self.mapped_view(view))))))))) |
| | | |
| | |
| | | |
| | | @wraps_view |
| | | def http_cached_view(self, view): |
| | | if self.registry.settings.get('prevent_http_cache', False): |
| | | return view |
| | | |
| | | seconds = self.kw.get('http_cache') |
| | | options = {} |
| | | |
| | | if seconds is None: |
| | | return view |
| | | |
| | | options = {} |
| | | |
| | | if isinstance(seconds, (tuple, list)): |
| | | try: |
| | |
| | | |
| | | def wrapper(context, request): |
| | | response = view(context, request) |
| | | cache_expires = getattr(response, 'cache_expires', None) |
| | | if cache_expires is not None: |
| | | cache_expires(seconds, **options) |
| | | prevent_caching = getattr(response.cache_control, 'prevent_auto', |
| | | False) |
| | | if not prevent_caching: |
| | | response.cache_expires(seconds, **options) |
| | | return response |
| | | |
| | | return wrapper |
| | |
| | | @wraps_view |
| | | def secured_view(self, view): |
| | | permission = self.kw.get('permission') |
| | | if permission == '__no_permission_required__': |
| | | if permission == NO_PERMISSION_REQUIRED: |
| | | # allow views registered within configurations that have a |
| | | # default permission to explicitly override the default |
| | | # permission, replacing it with no permission at all |
| | |
| | | |
| | | @wraps_view |
| | | def rendered_view(self, view): |
| | | wrapped_view = view |
| | | static_renderer = self.kw.get('renderer') |
| | | if static_renderer is None: |
| | | # one way or another this wrapper must produce a Response (unless |
| | | # the renderer is a NullRendererHelper) |
| | | renderer = self.kw.get('renderer') |
| | | if renderer is None: |
| | | # register a default renderer if you want super-dynamic |
| | | # rendering. registering a default renderer will also allow |
| | | # override_renderer to work if a renderer is left unspecified for |
| | | # a view registration. |
| | | return self._response_resolved_view(view) |
| | | if renderer is renderers.null_renderer: |
| | | return view |
| | | return self._rendered_view(view, renderer) |
| | | |
| | | def _rendered_view(context, request): |
| | | renderer = static_renderer |
| | | result = wrapped_view(context, request) |
| | | registry = self.kw['registry'] |
| | | def _rendered_view(self, view, view_renderer): |
| | | def rendered_view(context, request): |
| | | renderer = view_renderer |
| | | result = view(context, request) |
| | | registry = self.registry |
| | | # this must adapt, it can't do a simple interface check |
| | | # (avoid trying to render webob responses) |
| | | response = registry.queryAdapterOrSelf(result, IResponse) |
| | | if response is None: |
| | | attrs = getattr(request, '__dict__', {}) |
| | |
| | | if '__view__' in attrs: |
| | | view_inst = attrs.pop('__view__') |
| | | else: |
| | | view_inst = getattr(wrapped_view, '__original_view__', |
| | | wrapped_view) |
| | | view_inst = getattr(view, '__original_view__', view) |
| | | response = renderer.render_view(request, result, view_inst, |
| | | context) |
| | | return response |
| | | |
| | | return _rendered_view |
| | | return rendered_view |
| | | |
| | | def _response_resolved_view(self, view): |
| | | registry = self.registry |
| | | def viewresult_to_response(context, request): |
| | | result = view(context, request) |
| | | response = registry.queryAdapterOrSelf(result, IResponse) |
| | | if response is None: |
| | | raise ValueError( |
| | | 'Could not convert view return value "%s" into a ' |
| | | 'response object' % (result,)) |
| | | return response |
| | | |
| | | return viewresult_to_response |
| | | |
| | | @wraps_view |
| | | def decorated_view(self, view): |
| | |
| | | (inspect.isclass(o) and (issubclass(o, Exception))) |
| | | ) |
| | | |
| | | global_registries = WeakOrderedSet() |
| | | |
| | |
| | | event['mykey'] = 'foo' |
| | | |
| | | An object of this type is sent as an event just before a :term:`renderer` |
| | | is invoked (but *after* the application-level renderer globals factory |
| | | added via |
| | | :class:`pyramid.config.Configurator.set_renderer_globals_factory`, |
| | | if any, has injected its own keys into the renderer globals dictionary). |
| | | is invoked (but *after* the -- deprecated -- application-level renderer |
| | | globals factory added via |
| | | :class:`pyramid.config.Configurator.set_renderer_globals_factory`, if |
| | | any, has injected its own keys into the renderer globals dictionary). |
| | | |
| | | If a subscriber attempts to add a key that already exist in the renderer |
| | | globals dictionary, a :exc:`KeyError` is raised. This limitation is |
| | | enforced because event subscribers do not possess any relative ordering. |
| | | The set of keys added to the renderer globals dictionary by all |
| | | :class:`pyramid.events.BeforeRender` subscribers and renderer globals |
| | | factories must be unique. """ |
| | | If a subscriber adds a key via ``__setitem__`` or that already exists in |
| | | the renderer globals dictionary, it will overwrite an older value that is |
| | | already in the globals dictionary. This can be problematic because event |
| | | subscribers to the BeforeRender event do not possess any relative |
| | | ordering. For maximum interoperability with other third-party |
| | | subscribers, if you write an event subscriber meant to be used as a |
| | | BeforeRender subscriber, your subscriber code will need to (using |
| | | ``.get`` or ``__contains__`` of the event object) ensure no value already |
| | | exists in the renderer globals dictionary before setting an overriding |
| | | value. |
| | | |
| | | def __init__(self, system): |
| | | The event has an additional attribute named ``rendering_val``. This is |
| | | the (non-system) value returned by a view or passed to ``render*`` as |
| | | ``value``. This feature is new in Pyramid 1.1.1. |
| | | """ |
| | | |
| | | def __init__(self, system, rendering_val=None): |
| | | self._system = system |
| | | self.rendering_val = rendering_val |
| | | |
| | | def __setitem__(self, name, value): |
| | | """ Set a name/value pair into the dictionary which is passed to a |
| | | renderer as the renderer globals dictionary. If the ``name`` already |
| | | exists in the target dictionary, a :exc:`KeyError` will be raised.""" |
| | | if name in self._system: |
| | | raise KeyError('%s is already a renderer globals value' % name) |
| | | renderer as the renderer globals dictionary.""" |
| | | self._system[name] = value |
| | | |
| | | def setdefault(self, name, default=None): |
| | | """ Return the existing value for ``name`` in the renderers globals |
| | | dictionary. If no value with ``name`` exists in the dictionary, set |
| | | the ``default`` value into the renderer globals dictionary under the |
| | | name passed. If a value already existed in the dictionary, return |
| | | it. If a value did not exist in the dictionary, return the default""" |
| | | return self._system.setdefault(name, default) |
| | | |
| | | def update(self, d): |
| | | """ Update the renderer globals dictionary with another dictionary |
| | | ``d``. If any of the key names in the source dictionary already exist |
| | | in the target dictionary, a :exc:`KeyError` will be raised""" |
| | | for k, v in d.items(): |
| | | self[k] = v |
| | | ``d``.""" |
| | | return self._system.update(d) |
| | | |
| | | def __contains__(self, k): |
| | | """ Return ``True`` if ``k`` exists in the renderer globals |
| | |
| | | """ Return the value for key ``k`` from the renderer globals |
| | | dictionary, or the default if no such value exists.""" |
| | | return self._system.get(k) |
| | | |
| | | |
| | |
| | | if WSGIHTTPException.body_template_obj is not body_tmpl: |
| | | # Custom template; add headers to args |
| | | for k, v in environ.items(): |
| | | if (not k.startswith('wsgi.')) and ('.' in k): |
| | | # omit custom environ variables, stringifying them may |
| | | # trigger code that should not be executed here; see |
| | | # https://github.com/Pylons/pyramid/issues/239 |
| | | continue |
| | | args[k] = escape(v) |
| | | for k, v in self.headers.items(): |
| | | args[k.lower()] = escape(v) |
| | |
| | | :param fileobj: the file-like object the translation should be read |
| | | from |
| | | """ |
| | | # germanic plural by default; self.plural will be overwritten by |
| | | # GNUTranslations._parse (called as a side effect if fileobj is |
| | | # passed to GNUTranslations.__init__) with a "real" self.plural for |
| | | # this domain; see https://github.com/Pylons/pyramid/issues/235 |
| | | self.plural = lambda n: int(n != 1) |
| | | gettext.GNUTranslations.__init__(self, fp=fileobj) |
| | | self.files = filter(None, [getattr(fileobj, 'name', None)]) |
| | | self.domain = domain |
| | |
| | | """ |
| | | def __setitem__(name, value): |
| | | """ Set a name/value pair into the dictionary which is passed to a |
| | | renderer as the renderer globals dictionary. If the ``name`` already |
| | | exists in the target dictionary, a :exc:`KeyError` will be raised.""" |
| | | renderer as the renderer globals dictionary. """ |
| | | |
| | | def setdefault(name, default=None): |
| | | """ Return the existing value for ``name`` in the renderers globals |
| | | dictionary. If no value with ``name`` exists in the dictionary, set |
| | | the ``default`` value into the renderer globals dictionary under the |
| | | name passed. If a value already existed in the dictionary, return |
| | | it. If a value did not exist in the dictionary, return the default""" |
| | | |
| | | def update(d): |
| | | """ Update the renderer globals dictionary with another dictionary |
| | | ``d``. If any of the key names in the source dictionary already exist |
| | | in the target dictionary, a :exc:`KeyError` will be raised""" |
| | | ``d``. """ |
| | | |
| | | def __contains__(k): |
| | | """ Return ``True`` if ``k`` exists in the renderer globals |
| | |
| | | def get(k, default=None): |
| | | """ Return the value for key ``k`` from the renderer globals |
| | | dictionary, or the default if no such value exists.""" |
| | | |
| | | rendering_val = Attribute('The value returned by a view or passed to a ' |
| | | '``render`` method for this rendering. ' |
| | | 'This feature is new in Pyramid 1.1.1.') |
| | | |
| | | class IRenderer(Interface): |
| | | def __call__(value, system): |
| | |
| | | |
| | | class IRequest(Interface): |
| | | """ Request type interface attached to all request objects """ |
| | | |
| | | class ITweens(Interface): |
| | | """ Marker interface for utility registration representing the ordered |
| | | set of a configuration's tween factories""" |
| | | |
| | | class IRequestHandler(Interface): |
| | | """ """ |
| | | def __call__(self, request): |
| | | """ Must return a tuple of IReqest, IResponse or raise an exception. |
| | | The ``request`` argument will be an instance of an object that |
| | | provides IRequest.""" |
| | | |
| | | IRequest.combined = IRequest # for exception view lookups |
| | | |
| | |
| | | 'when this route matches (or ``None``)') |
| | | predicates = Attribute( |
| | | 'A sequence of :term:`route predicate` objects used to ' |
| | | 'determine if a request matches this route or not or not after ' |
| | | 'determine if a request matches this route or not after ' |
| | | 'basic pattern matching has been completed.') |
| | | pregenerator = Attribute('This attribute should either be ``None`` or ' |
| | | 'a callable object implementing the ' |
| | |
| | | """ Pop a queue from the flash storage. The queue is removed from |
| | | flash storage after this message is called. The queue is returned; |
| | | it is a list of flash messages added by |
| | | :meth:`pyramid.interfaces.ISesssion.flash`""" |
| | | :meth:`pyramid.interfaces.ISession.flash`""" |
| | | |
| | | def peek_flash(queue=''): |
| | | """ Peek at a queue in the flash storage. The queue remains in |
| | | flash storage after this message is called. The queue is returned; |
| | | it is a list of flash messages added by |
| | | :meth:`pyramid.interfaces.ISesssion.flash` |
| | | :meth:`pyramid.interfaces.ISession.flash` |
| | | """ |
| | | |
| | | def new_csrf_token(): |
| | |
| | | def __contains__(key): |
| | | """Return true if a key exists in the mapping.""" |
| | | |
| | | NO_PERMISSION_REQUIRED = '__no_permission_required__' |
| | | |
| | | class IRendererInfo(Interface): |
| | | """ An object implementing this interface is passed to every |
| | | :term:`renderer factory` constructor as its only argument (conventionally |
| | |
| | | settings = Attribute('The deployment settings dictionary related ' |
| | | 'to the current application') |
| | | |
| | | |
| | |
| | | import ConfigParser |
| | | import os |
| | | import sys |
| | | from code import interact |
| | |
| | | from paste.deploy import loadapp |
| | | from paste.script.command import Command |
| | | |
| | | from pyramid.scripting import get_root |
| | | from pyramid.interfaces import IMultiView |
| | | from pyramid.interfaces import ITweens |
| | | |
| | | from pyramid.scripting import prepare |
| | | from pyramid.util import DottedNameResolver |
| | | |
| | | from pyramid.tweens import MAIN |
| | | from pyramid.tweens import INGRESS |
| | | |
| | | from pyramid.scaffolds import PyramidTemplate # bw compat |
| | | zope.deprecation.deprecated( |
| | |
| | | 'pyramid.scaffolds.PyramidTemplate in Pyramid 1.1'), |
| | | ) |
| | | |
| | | def get_app(config_file, name, loadapp=loadapp): |
| | | def get_app(config_uri, name=None, loadapp=loadapp): |
| | | """ Return the WSGI application named ``name`` in the PasteDeploy |
| | | config file ``config_file``""" |
| | | config_name = 'config:%s' % config_file |
| | | config file specified by ``config_uri``. |
| | | |
| | | If the ``name`` is None, this will attempt to parse the name from |
| | | the ``config_uri`` string expecting the format ``inifile#name``. |
| | | If no name is found, the name will default to "main".""" |
| | | if '#' in config_uri: |
| | | path, section = config_uri.split('#', 1) |
| | | else: |
| | | path, section = config_uri, 'main' |
| | | if name: |
| | | section = name |
| | | config_name = 'config:%s' % path |
| | | here_dir = os.getcwd() |
| | | app = loadapp(config_name, name=name, relative_to=here_dir) |
| | | app = loadapp(config_name, name=section, relative_to=here_dir) |
| | | return app |
| | | |
| | | _marker = object() |
| | | def bootstrap(config_uri, request=None): |
| | | """ Load a WSGI application from the PasteDeploy config file specified |
| | | by ``config_uri``. The environment will be configured as if it is |
| | | currently serving ``request``, leaving a natural environment in place |
| | | to write scripts that can generate URLs and utilize renderers. |
| | | |
| | | This function returns a dictionary with ``app``, ``root``, ``closer``, |
| | | ``request``, and ``registry`` keys. ``app`` is the WSGI app loaded |
| | | (based on the ``config_uri``), ``root`` is the traversal root resource |
| | | of the Pyramid application, and ``closer`` is a parameterless callback |
| | | that may be called when your script is complete (it pops a threadlocal |
| | | stack). |
| | | |
| | | .. note:: Most operations within :app:`Pyramid` expect to be invoked |
| | | within the context of a WSGI request, thus it's important when |
| | | loading your application to anchor it when executing scripts |
| | | and other code that is not normally invoked during active WSGI |
| | | requests. |
| | | |
| | | .. note:: For a complex config file containing multiple :app:`Pyramid` |
| | | applications, this function will setup the environment under |
| | | the context of the last-loaded :app:`Pyramid` application. You |
| | | may load a specific application yourself by using the |
| | | lower-level functions :meth:`pyramid.paster.get_app` and |
| | | :meth:`pyramid.scripting.prepare` in conjunction with |
| | | :attr:`pyramid.config.global_registries`. |
| | | |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | ``request`` -- specified to anchor the script to a given set of WSGI |
| | | parameters. For example, most people would want to specify the host, |
| | | scheme and port such that their script will generate URLs in relation |
| | | to those parameters. A request with default parameters is constructed |
| | | for you if none is provided. You can mutate the request's ``environ`` |
| | | later to setup a specific host/port/scheme/etc. |
| | | |
| | | See :ref:`writing_a_script` for more information about how to use this |
| | | function. |
| | | """ |
| | | app = get_app(config_uri) |
| | | env = prepare(request) |
| | | env['app'] = app |
| | | return env |
| | | |
| | | class PCommand(Command): |
| | | get_app = staticmethod(get_app) # hook point |
| | | get_root = staticmethod(get_root) # hook point |
| | | group_name = 'pyramid' |
| | | interact = (interact,) # for testing |
| | | loadapp = (loadapp,) # for testing |
| | | bootstrap = (bootstrap,) # testing |
| | | verbose = 3 |
| | | |
| | | def __init__(self, *arg, **kw): |
| | |
| | | class PShellCommand(PCommand): |
| | | """Open an interactive shell with a :app:`Pyramid` app loaded. |
| | | |
| | | This command accepts two positional arguments: |
| | | This command accepts one positional argument: |
| | | |
| | | ``config_file`` -- specifies the PasteDeploy config file to use |
| | | for the interactive shell. |
| | | |
| | | ``section_name`` -- specifies the section name in the PasteDeploy |
| | | config file that represents the application. |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | Example:: |
| | | |
| | | $ paster pshell myapp.ini main |
| | | $ paster pshell myapp.ini#main |
| | | |
| | | .. note:: You should use a ``section_name`` that refers to the |
| | | actual ``app`` section in the config file that points at |
| | | your Pyramid app without any middleware wrapping, or this |
| | | command will almost certainly fail. |
| | | .. note:: If you do not point the loader directly at the section of the |
| | | ini file containing your :app:`Pyramid` application, the |
| | | command will attempt to find the app for you. If you are |
| | | loading a pipeline that contains more than one :app:`Pyramid` |
| | | application within it, the loader will use the last one. |
| | | |
| | | """ |
| | | summary = "Open an interactive shell with a Pyramid application loaded" |
| | | |
| | | min_args = 2 |
| | | max_args = 2 |
| | | min_args = 1 |
| | | max_args = 1 |
| | | |
| | | parser = Command.standard_parser(simulate=True) |
| | | parser.add_option('-d', '--disable-ipython', |
| | |
| | | dest='disable_ipython', |
| | | help="Don't use IPython even if it is available") |
| | | |
| | | def command(self, IPShell=_marker): |
| | | # IPShell passed to command method is for testing purposes |
| | | if IPShell is _marker: # pragma: no cover |
| | | try: |
| | | from IPython.Shell import IPShell |
| | | except ImportError: |
| | | IPShell = None |
| | | cprt =('Type "help" for more information. "root" is the Pyramid app ' |
| | | 'root object, "registry" is the Pyramid registry object.') |
| | | banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt) |
| | | config_file, section_name = self.args |
| | | self.logging_file_config(config_file) |
| | | app = self.get_app(config_file, section_name, loadapp=self.loadapp[0]) |
| | | root, closer = self.get_root(app) |
| | | shell_globals = {'root':root, 'registry':app.registry} |
| | | ConfigParser = ConfigParser.ConfigParser # testing |
| | | |
| | | if (IPShell is None) or self.options.disable_ipython: |
| | | def pshell_file_config(self, filename): |
| | | resolver = DottedNameResolver(None) |
| | | self.loaded_objects = {} |
| | | self.object_help = {} |
| | | config = self.ConfigParser() |
| | | config.read(filename) |
| | | try: |
| | | items = config.items('pshell') |
| | | except ConfigParser.NoSectionError: |
| | | return |
| | | for k, v in items: |
| | | self.loaded_objects[k] = resolver.maybe_resolve(v) |
| | | self.object_help[k] = v |
| | | |
| | | def command(self, shell=None): |
| | | config_uri = self.args[0] |
| | | config_file = config_uri.split('#', 1)[0] |
| | | self.logging_file_config(config_file) |
| | | self.pshell_file_config(config_file) |
| | | |
| | | # bootstrap the environ |
| | | env = self.bootstrap[0](config_uri) |
| | | |
| | | # remove the closer from the env |
| | | closer = env.pop('closer') |
| | | |
| | | # setup help text for default environment |
| | | env_help = dict(env) |
| | | env_help['app'] = 'The WSGI application.' |
| | | env_help['root'] = 'Root of the default resource tree.' |
| | | env_help['registry'] = 'Active Pyramid registry.' |
| | | env_help['request'] = 'Active request object.' |
| | | env_help['root_factory'] = ( |
| | | 'Default root factory used to create `root`.') |
| | | |
| | | # load the pshell section of the ini file |
| | | env.update(self.loaded_objects) |
| | | |
| | | # eliminate duplicates from env, allowing custom vars to override |
| | | for k in self.loaded_objects: |
| | | if k in env_help: |
| | | del env_help[k] |
| | | |
| | | # generate help text |
| | | help = '\n' |
| | | if env_help: |
| | | help += 'Environment:' |
| | | for var in sorted(env_help.keys()): |
| | | help += '\n %-12s %s' % (var, env_help[var]) |
| | | |
| | | if self.object_help: |
| | | help += '\n\nCustom Variables:' |
| | | for var in sorted(self.object_help.keys()): |
| | | help += '\n %-12s %s' % (var, self.object_help[var]) |
| | | |
| | | if shell is None and not self.options.disable_ipython: |
| | | shell = self.make_ipython_v0_11_shell() |
| | | if shell is None: |
| | | shell = self.make_ipython_v0_10_shell() |
| | | |
| | | if shell is None: |
| | | shell = self.make_default_shell() |
| | | |
| | | try: |
| | | shell(env, help) |
| | | finally: |
| | | closer() |
| | | |
| | | def make_default_shell(self, interact=interact): |
| | | def shell(env, help): |
| | | cprt = 'Type "help" for more information.' |
| | | banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt) |
| | | banner += '\n' + help + '\n' |
| | | interact(banner, local=env) |
| | | return shell |
| | | |
| | | def make_ipython_v0_11_shell(self, IPShellFactory=None): |
| | | if IPShellFactory is None: # pragma: no cover |
| | | try: |
| | | self.interact[0](banner, local=shell_globals) |
| | | finally: |
| | | closer() |
| | | else: |
| | | from IPython.frontend.terminal.embed import ( |
| | | InteractiveShellEmbed) |
| | | IPShellFactory = InteractiveShellEmbed |
| | | except ImportError: |
| | | return None |
| | | def shell(env, help): |
| | | IPShell = IPShellFactory(banner2=help, user_ns=env) |
| | | IPShell() |
| | | return shell |
| | | |
| | | def make_ipython_v0_10_shell(self, IPShellFactory=None): |
| | | if IPShellFactory is None: # pragma: no cover |
| | | try: |
| | | shell = IPShell(argv=[], user_ns=shell_globals) |
| | | shell.IP.BANNER = shell.IP.BANNER + '\n\n' + banner |
| | | shell.mainloop() |
| | | finally: |
| | | closer() |
| | | from IPython.Shell import IPShellEmbed |
| | | IPShellFactory = IPShellEmbed |
| | | except ImportError: |
| | | return None |
| | | def shell(env, help): |
| | | IPShell = IPShellFactory(argv=[], user_ns=env) |
| | | IPShell.set_banner(IPShell.IP.BANNER + '\n' + help + '\n') |
| | | IPShell() |
| | | return shell |
| | | |
| | | BFGShellCommand = PShellCommand # b/w compat forever |
| | | |
| | |
| | | route, the pattern of the route, and the view callable which will be |
| | | invoked when the route is matched. |
| | | |
| | | This command accepts two positional arguments: |
| | | This command accepts one positional argument: |
| | | |
| | | ``config_file`` -- specifies the PasteDeploy config file to use |
| | | for the interactive shell. |
| | | |
| | | ``section_name`` -- specifies the section name in the PasteDeploy |
| | | config file that represents the application. |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | Example:: |
| | | |
| | | $ paster proutes myapp.ini main |
| | | $ paster proutes myapp.ini#main |
| | | |
| | | .. note:: You should use a ``section_name`` that refers to the |
| | | actual ``app`` section in the config file that points at |
| | | your Pyramid app without any middleware wrapping, or this |
| | | command will almost certainly fail. |
| | | """ |
| | | summary = "Print all URL dispatch routes related to a Pyramid application" |
| | | min_args = 2 |
| | | max_args = 2 |
| | | min_args = 1 |
| | | max_args = 1 |
| | | stdout = sys.stdout |
| | | |
| | | parser = Command.standard_parser(simulate=True) |
| | | |
| | | def _get_mapper(self, app): |
| | | def _get_mapper(self, registry): |
| | | from pyramid.config import Configurator |
| | | registry = app.registry |
| | | config = Configurator(registry = registry) |
| | | return config.get_routes_mapper() |
| | | |
| | |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IView |
| | | from zope.interface import Interface |
| | | config_file, section_name = self.args |
| | | app = self.get_app(config_file, section_name, loadapp=self.loadapp[0]) |
| | | registry = app.registry |
| | | mapper = self._get_mapper(app) |
| | | config_uri = self.args[0] |
| | | env = self.bootstrap[0](config_uri) |
| | | registry = env['registry'] |
| | | mapper = self._get_mapper(registry) |
| | | if mapper is not None: |
| | | routes = mapper.get_routes() |
| | | fmt = '%-15s %-30s %-25s' |
| | |
| | | self.out(fmt % (route.name, route.pattern, view_callable)) |
| | | |
| | | |
| | | from pyramid.interfaces import IMultiView |
| | | |
| | | class PViewsCommand(PCommand): |
| | | """Print, for a given URL, the views that might match. Underneath each |
| | | potentially matching route, list the predicates required. Underneath |
| | | each route+predicate set, print each view that might match and its |
| | | predicates. |
| | | |
| | | This command accepts three positional arguments: |
| | | This command accepts two positional arguments: |
| | | |
| | | ``config_file`` -- specifies the PasteDeploy config file to use |
| | | for the interactive shell. |
| | | |
| | | ``section_name`` -- specifies the section name in the PasteDeploy |
| | | config file that represents the application. |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | ``url`` -- specifies the URL that will be used to find matching views. |
| | | |
| | | Example:: |
| | | |
| | | $ paster proutes myapp.ini main url |
| | | $ paster proutes myapp.ini#main url |
| | | |
| | | .. note:: You should use a ``section_name`` that refers to the |
| | | actual ``app`` section in the config file that points at |
| | | your Pyramid app without any middleware wrapping, or this |
| | | command will almost certainly fail. |
| | | """ |
| | | summary = "Print all views in an application that might match a URL" |
| | | min_args = 3 |
| | | max_args = 3 |
| | | min_args = 2 |
| | | max_args = 2 |
| | | stdout = sys.stdout |
| | | |
| | | parser = Command.standard_parser(simulate=True) |
| | |
| | | self.out("%sview predicates (%s)" % (indent, predicate_text)) |
| | | |
| | | def command(self): |
| | | config_file, section_name, url = self.args |
| | | config_uri, url = self.args |
| | | if not url.startswith('/'): |
| | | url = '/%s' % url |
| | | app = self.get_app(config_file, section_name, loadapp=self.loadapp[0]) |
| | | registry = app.registry |
| | | env = self.bootstrap[0](config_uri) |
| | | registry = env['registry'] |
| | | view = self._find_view(url, registry) |
| | | self.out('') |
| | | self.out("URL = %s" % url) |
| | |
| | | self.out(" Not found.") |
| | | self.out('') |
| | | |
| | | |
| | | class PTweensCommand(PCommand): |
| | | """Print all implicit and explicit :term:`tween` objects used by a |
| | | Pyramid application. The handler output includes whether the system is |
| | | using an explicit tweens ordering (will be true when the |
| | | ``pyramid.tweens`` setting is used) or an implicit tweens ordering (will |
| | | be true when the ``pyramid.tweens`` setting is *not* used). |
| | | |
| | | This command accepts one positional argument: |
| | | |
| | | ``config_uri`` -- specifies the PasteDeploy config file to use for the |
| | | interactive shell. The format is ``inifile#name``. If the name is left |
| | | off, ``main`` will be assumed. |
| | | |
| | | Example:: |
| | | |
| | | $ paster ptweens myapp.ini#main |
| | | |
| | | """ |
| | | summary = "Print all tweens related to a Pyramid application" |
| | | min_args = 1 |
| | | max_args = 1 |
| | | stdout = sys.stdout |
| | | |
| | | parser = Command.standard_parser(simulate=True) |
| | | |
| | | def _get_tweens(self, registry): |
| | | from pyramid.config import Configurator |
| | | config = Configurator(registry = registry) |
| | | return config.registry.queryUtility(ITweens) |
| | | |
| | | def out(self, msg): # pragma: no cover |
| | | print msg |
| | | |
| | | def show_implicit(self, tweens): |
| | | implicit = tweens.implicit() |
| | | fmt = '%-10s %-50s %-15s' |
| | | self.out(fmt % ('Position', 'Name', 'Alias')) |
| | | self.out(fmt % ( |
| | | '-'*len('Position'), '-'*len('Name'), '-'*len('Alias'))) |
| | | self.out(fmt % ('-', '-', INGRESS)) |
| | | for pos, (name, _) in enumerate(implicit): |
| | | alias = tweens.name_to_alias.get(name, None) |
| | | self.out(fmt % (pos, name, alias)) |
| | | self.out(fmt % ('-', '-', MAIN)) |
| | | |
| | | def show_explicit(self, tweens): |
| | | explicit = tweens.explicit |
| | | fmt = '%-10s %-65s' |
| | | self.out(fmt % ('Position', 'Name')) |
| | | self.out(fmt % ('-'*len('Position'), '-'*len('Name'))) |
| | | self.out(fmt % ('-', INGRESS)) |
| | | for pos, (name, _) in enumerate(explicit): |
| | | self.out(fmt % (pos, name)) |
| | | self.out(fmt % ('-', MAIN)) |
| | | |
| | | def command(self): |
| | | config_uri = self.args[0] |
| | | env = self.bootstrap[0](config_uri) |
| | | registry = env['registry'] |
| | | tweens = self._get_tweens(registry) |
| | | if tweens is not None: |
| | | explicit = tweens.explicit |
| | | if explicit: |
| | | self.out('"pyramid.tweens" config value set ' |
| | | '(explicitly ordered tweens used)') |
| | | self.out('') |
| | | self.out('Explicit Tween Chain (used)') |
| | | self.out('') |
| | | self.show_explicit(tweens) |
| | | self.out('') |
| | | self.out('Implicit Tween Chain (not used)') |
| | | self.out('') |
| | | self.show_implicit(tweens) |
| | | else: |
| | | self.out('"pyramid.tweens" config value NOT set ' |
| | | '(implicitly ordered tweens used)') |
| | | self.out('') |
| | | self.out('Implicit Tween Chain') |
| | | self.out('') |
| | | self.show_implicit(tweens) |
| | |
| | | import threading |
| | | |
| | | from zope.interface import implements |
| | | from zope.deprecation import deprecated |
| | | |
| | | from pyramid.interfaces import IChameleonLookup |
| | | from pyramid.interfaces import IChameleonTranslate |
| | |
| | | |
| | | Supply a ``request`` parameter in order to provide the renderer |
| | | with the most correct 'system' values (``request`` and ``context`` |
| | | in particular). |
| | | in particular). Keep in mind that if the ``request`` parameter is |
| | | not passed in, any changes to ``request.response`` attributes made |
| | | before calling this function will be ignored. |
| | | |
| | | """ |
| | | try: |
| | |
| | | lock.release() |
| | | return lookup(info) |
| | | |
| | | # XXX deprecate |
| | | def renderer_from_name(path, package=None): |
| | | return RendererHelper(name=path, package=package).renderer |
| | | |
| | | deprecated( |
| | | 'renderer_from_name', |
| | | 'The "pyramid.renderers.renderer_from_name" function was never an API. ' |
| | | 'However, its use has been observed "in the wild." It will disappear in ' |
| | | 'the next major release. To replace it, use the ' |
| | | '``pyramid.renderers.get_renderer`` API instead. ') |
| | | |
| | | class RendererHelper(object): |
| | | implements(IRendererInfo) |
| | |
| | | if name and '.' in name: |
| | | rtype = os.path.splitext(name)[1] |
| | | else: |
| | | rtype = name |
| | | # important.. must be a string; cannot be None; see issue 249 |
| | | rtype = name or '' |
| | | |
| | | if registry is None: |
| | | registry = get_current_registry() |
| | |
| | | if renderer_globals: |
| | | system_values.update(renderer_globals) |
| | | |
| | | registry.notify(BeforeRender(system_values)) |
| | | registry.notify(BeforeRender(system_values, value)) |
| | | |
| | | result = renderer(value, system_values) |
| | | return result |
| | |
| | | return self._make_response(result, request) |
| | | |
| | | def _make_response(self, result, request): |
| | | # broken out of render_to_response as a separate method for testing |
| | | # purposes |
| | | response = getattr(request, 'response', None) |
| | | if response is None: |
| | | # request is None or request is not a pyramid.response.Response |
| | |
| | | response.cache_expires = cache_for |
| | | return response |
| | | |
| | | def clone(self, name=None, package=None, registry=None): |
| | | if name is None: |
| | | name = self.name |
| | | if package is None: |
| | | package = self.package |
| | | if registry is None: |
| | | registry = self.registry |
| | | return self.__class__(name=name, package=package, registry=registry) |
| | | |
| | | class NullRendererHelper(RendererHelper): |
| | | """ Special renderer helper that has render_* methods which simply return |
| | | the value they are fed rather than converting them to response objects; |
| | | useful for testing purposes and special case view configuration |
| | | registrations that want to use the view configuration machinery but do |
| | | not want actual rendering to happen .""" |
| | | def __init__(self, name=None, package=None, registry=None): |
| | | # we override the initializer to avoid calling get_current_registry |
| | | # (it will return a reference to the global registry when this |
| | | # thing is called at module scope; we don't want that). |
| | | self.name = None |
| | | self.package = None |
| | | self.type = '' |
| | | self.registry = None |
| | | |
| | | @property |
| | | def settings(self): |
| | | return get_current_registry().settings or {} |
| | | |
| | | def render_view(self, request, value, view, context): |
| | | return value |
| | | |
| | | def render(self, value, system_values, request=None): |
| | | return value |
| | | |
| | | def render_to_response(self, value, system_values, request=None): |
| | | return value |
| | | |
| | | def clone(self, name=None, package=None, registry=None): |
| | | return self |
| | | |
| | | null_renderer = NullRendererHelper() |
| | |
| | | response_callbacks = () |
| | | finished_callbacks = () |
| | | exception = None |
| | | exc_info = None |
| | | matchdict = None |
| | | matched_route = None |
| | | |
| | |
| | | return adapted is ob |
| | | |
| | | @property |
| | | def json(self): |
| | | if self.content_type == 'application/json': |
| | | return json.loads(self.body, encoding=self.charset) |
| | | def json_body(self): |
| | | return json.loads(self.body, encoding=self.charset) |
| | | |
| | | |
| | | def route_request_iface(name, bases=()): |
| | | iface = InterfaceClass('%s_IRequest' % name, bases=bases) |
| | | # zope.interface treats the __name__ as the __doc__ and changes __name__ |
| | | # to None for interfaces that contain spaces if you do not pass a |
| | | # nonempty __doc__ (insane); see |
| | | # zope.interface.interface.Element.__init__ and |
| | | # https://github.com/Pylons/pyramid/issues/232; as a result, always pass |
| | | # __doc__ to the InterfaceClass constructor. |
| | | iface = InterfaceClass('%s_IRequest' % name, bases=bases, |
| | | __doc__="route_request_iface-generated interface") |
| | | # for exception view lookups |
| | | iface.combined = InterfaceClass('%s_combined_IRequest' % name, |
| | | bases=(iface, IRequest)) |
| | | iface.combined = InterfaceClass( |
| | | '%s_combined_IRequest' % name, |
| | | bases=(iface, IRequest), |
| | | __doc__ = 'route_request_iface-generated combined interface') |
| | | return iface |
| | | |
| | | def add_global_response_headers(request, headerlist): |
| | |
| | | import venusian |
| | | |
| | | from webob import Response as _Response |
| | | from zope.interface import implements |
| | | from pyramid.interfaces import IResponse |
| | |
| | | class Response(_Response): |
| | | implements(IResponse) |
| | | |
| | | |
| | | class response_adapter(object): |
| | | """ Decorator activated via a :term:`scan` which treats the function |
| | | being decorated as a :term:`response adapter` for the set of types or |
| | | interfaces passed as ``*types_or_ifaces`` to the decorator constructor. |
| | | |
| | | For example, if you scan the following response adapter: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.response import Response |
| | | from pyramid.response import response_adapter |
| | | |
| | | @response_adapter(int) |
| | | def myadapter(i): |
| | | return Response(status=i) |
| | | |
| | | You can then return an integer from your view callables, and it will be |
| | | converted into a response with the integer as the status code. |
| | | |
| | | More than one type or interface can be passed as a constructor argument. |
| | | The decorated response adapter will be called for each type or interface. |
| | | |
| | | .. code-block:: python |
| | | |
| | | import json |
| | | |
| | | from pyramid.response import Response |
| | | from pyramid.response import response_adapter |
| | | |
| | | @response_adapter(dict, list) |
| | | def myadapter(ob): |
| | | return Response(json.dumps(ob)) |
| | | |
| | | This method will have no effect until a :term:`scan` is performed |
| | | agains the package or module which contains it, ala: |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.config import Configurator |
| | | config = Configurator() |
| | | config.scan('somepackage_containing_adapters') |
| | | |
| | | """ |
| | | venusian = venusian # for unit testing |
| | | |
| | | def __init__(self, *types_or_ifaces): |
| | | self.types_or_ifaces = types_or_ifaces |
| | | |
| | | def register(self, scanner, name, wrapped): |
| | | config = scanner.config |
| | | for type_or_iface in self.types_or_ifaces: |
| | | config.add_response_adapter(wrapped, type_or_iface) |
| | | |
| | | def __call__(self, wrapped): |
| | | self.venusian.attach(wrapped, self.register, category='pyramid') |
| | | return wrapped |
| | |
| | | from zope.interface import providedBy |
| | | |
| | | from pyramid.interfaces import IDebugLogger |
| | | from pyramid.interfaces import IExceptionViewClassifier |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IRootFactory |
| | | from pyramid.interfaces import IRouteRequest |
| | |
| | | from pyramid.interfaces import ITraverser |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IResponse |
| | | from pyramid.interfaces import ITweens |
| | | |
| | | from pyramid.events import ContextFound |
| | | from pyramid.events import NewRequest |
| | |
| | | from pyramid.threadlocal import manager |
| | | from pyramid.traversal import DefaultRootFactory |
| | | from pyramid.traversal import ResourceTreeTraverser |
| | | from pyramid.tweens import excview_tween_factory |
| | | |
| | | class Router(object): |
| | | implements(IRouter) |
| | |
| | | self.root_factory = q(IRootFactory, default=DefaultRootFactory) |
| | | self.routes_mapper = q(IRoutesMapper) |
| | | self.request_factory = q(IRequestFactory, default=Request) |
| | | tweens = q(ITweens) |
| | | if tweens is None: |
| | | tweens = excview_tween_factory |
| | | self.handle_request = tweens(self.handle_request, registry) |
| | | self.root_policy = self.root_factory # b/w compat |
| | | self.registry = registry |
| | | settings = registry.settings |
| | | |
| | | if settings is not None: |
| | | self.debug_notfound = settings['debug_notfound'] |
| | | self.debug_routematch = settings['debug_routematch'] |
| | | |
| | | def handle_request(self, request): |
| | | attrs = request.__dict__ |
| | | registry = attrs['registry'] |
| | | |
| | | request.request_iface = IRequest |
| | | context = None |
| | | routes_mapper = self.routes_mapper |
| | | debug_routematch = self.debug_routematch |
| | | adapters = registry.adapters |
| | | has_listeners = registry.has_listeners |
| | | notify = registry.notify |
| | | logger = self.logger |
| | | |
| | | has_listeners and notify(NewRequest(request)) |
| | | # find the root object |
| | | root_factory = self.root_factory |
| | | if routes_mapper is not None: |
| | | info = routes_mapper(request) |
| | | match, route = info['match'], info['route'] |
| | | if route is None: |
| | | if debug_routematch: |
| | | msg = ('no route matched for url %s' % |
| | | request.url) |
| | | logger and logger.debug(msg) |
| | | else: |
| | | # TODO: kill off bfg.routes.* environ keys |
| | | # when traverser requires request arg, and |
| | | # cant cope with environ anymore (they are |
| | | # docs-deprecated as of BFG 1.3) |
| | | environ = request.environ |
| | | environ['bfg.routes.route'] = route |
| | | environ['bfg.routes.matchdict'] = match |
| | | attrs['matchdict'] = match |
| | | attrs['matched_route'] = route |
| | | |
| | | if debug_routematch: |
| | | msg = ( |
| | | 'route matched for url %s; ' |
| | | 'route_name: %r, ' |
| | | 'path_info: %r, ' |
| | | 'pattern: %r, ' |
| | | 'matchdict: %r, ' |
| | | 'predicates: %r' % ( |
| | | request.url, |
| | | route.name, |
| | | request.path_info, |
| | | route.pattern, match, |
| | | route.predicates) |
| | | ) |
| | | logger and logger.debug(msg) |
| | | |
| | | request.request_iface = registry.queryUtility( |
| | | IRouteRequest, |
| | | name=route.name, |
| | | default=IRequest) |
| | | |
| | | root_factory = route.factory or self.root_factory |
| | | |
| | | root = root_factory(request) |
| | | attrs['root'] = root |
| | | |
| | | # find a context |
| | | traverser = adapters.queryAdapter(root, ITraverser) |
| | | if traverser is None: |
| | | traverser = ResourceTreeTraverser(root) |
| | | tdict = traverser(request) |
| | | |
| | | context, view_name, subpath, traversed, vroot, vroot_path = ( |
| | | tdict['context'], |
| | | tdict['view_name'], |
| | | tdict['subpath'], |
| | | tdict['traversed'], |
| | | tdict['virtual_root'], |
| | | tdict['virtual_root_path'] |
| | | ) |
| | | |
| | | attrs.update(tdict) |
| | | has_listeners and notify(ContextFound(request)) |
| | | |
| | | # find a view callable |
| | | context_iface = providedBy(context) |
| | | view_callable = adapters.lookup( |
| | | (IViewClassifier, request.request_iface, context_iface), |
| | | IView, name=view_name, default=None) |
| | | |
| | | # invoke the view callable |
| | | if view_callable is None: |
| | | if self.debug_notfound: |
| | | msg = ( |
| | | 'debug_notfound of url %s; path_info: %r, ' |
| | | 'context: %r, view_name: %r, subpath: %r, ' |
| | | 'traversed: %r, root: %r, vroot: %r, ' |
| | | 'vroot_path: %r' % ( |
| | | request.url, request.path_info, context, |
| | | view_name, subpath, traversed, root, vroot, |
| | | vroot_path) |
| | | ) |
| | | logger and logger.debug(msg) |
| | | else: |
| | | msg = request.path_info |
| | | raise HTTPNotFound(msg) |
| | | else: |
| | | response = view_callable(context, request) |
| | | |
| | | return response |
| | | |
| | | def __call__(self, environ, start_response): |
| | | """ |
| | |
| | | return an iterable. |
| | | """ |
| | | registry = self.registry |
| | | adapters = registry.adapters |
| | | has_listeners = registry.has_listeners |
| | | notify = registry.notify |
| | | logger = self.logger |
| | | manager = self.threadlocal_manager |
| | | routes_mapper = self.routes_mapper |
| | | debug_routematch = self.debug_routematch |
| | | request = None |
| | | has_listeners = self.registry.has_listeners |
| | | notify = self.registry.notify |
| | | request = self.request_factory(environ) |
| | | threadlocals = {'registry':registry, 'request':request} |
| | | manager = self.threadlocal_manager |
| | | manager.push(threadlocals) |
| | | request.registry = registry |
| | | try: |
| | | |
| | | try: # matches finally: manager.pop() |
| | | |
| | | try: # matches finally: ... call request finished callbacks ... |
| | | |
| | | # create the request |
| | | request = self.request_factory(environ) |
| | | context = None |
| | | threadlocals['request'] = request |
| | | attrs = request.__dict__ |
| | | attrs['registry'] = registry |
| | | request_iface = IRequest |
| | | |
| | | try: # matches except Exception (exception view execution) |
| | | has_listeners and notify(NewRequest(request)) |
| | | # find the root object |
| | | root_factory = self.root_factory |
| | | if routes_mapper is not None: |
| | | info = routes_mapper(request) |
| | | match, route = info['match'], info['route'] |
| | | if route is None: |
| | | if debug_routematch: |
| | | msg = ('no route matched for url %s' % |
| | | request.url) |
| | | logger and logger.debug(msg) |
| | | else: |
| | | # TODO: kill off bfg.routes.* environ keys when |
| | | # traverser requires request arg, and cant cope |
| | | # with environ anymore (they are docs-deprecated as |
| | | # of BFG 1.3) |
| | | environ['bfg.routes.route'] = route |
| | | environ['bfg.routes.matchdict'] = match |
| | | attrs['matchdict'] = match |
| | | attrs['matched_route'] = route |
| | | |
| | | if debug_routematch: |
| | | msg = ( |
| | | 'route matched for url %s; ' |
| | | 'route_name: %r, ' |
| | | 'path_info: %r, ' |
| | | 'pattern: %r, ' |
| | | 'matchdict: %r, ' |
| | | 'predicates: %r' % ( |
| | | request.url, |
| | | route.name, |
| | | request.path_info, |
| | | route.pattern, match, |
| | | route.predicates) |
| | | ) |
| | | logger and logger.debug(msg) |
| | | |
| | | request_iface = registry.queryUtility( |
| | | IRouteRequest, |
| | | name=route.name, |
| | | default=IRequest) |
| | | root_factory = route.factory or self.root_factory |
| | | |
| | | root = root_factory(request) |
| | | attrs['root'] = root |
| | | |
| | | # find a context |
| | | traverser = adapters.queryAdapter(root, ITraverser) |
| | | if traverser is None: |
| | | traverser = ResourceTreeTraverser(root) |
| | | tdict = traverser(request) |
| | | context, view_name, subpath, traversed, vroot, vroot_path =( |
| | | tdict['context'], tdict['view_name'], tdict['subpath'], |
| | | tdict['traversed'], tdict['virtual_root'], |
| | | tdict['virtual_root_path']) |
| | | attrs.update(tdict) |
| | | has_listeners and notify(ContextFound(request)) |
| | | |
| | | # find a view callable |
| | | context_iface = providedBy(context) |
| | | view_callable = adapters.lookup( |
| | | (IViewClassifier, request_iface, context_iface), |
| | | IView, name=view_name, default=None) |
| | | |
| | | # invoke the view callable |
| | | if view_callable is None: |
| | | if self.debug_notfound: |
| | | msg = ( |
| | | 'debug_notfound of url %s; path_info: %r, ' |
| | | 'context: %r, view_name: %r, subpath: %r, ' |
| | | 'traversed: %r, root: %r, vroot: %r, ' |
| | | 'vroot_path: %r' % ( |
| | | request.url, request.path_info, context, |
| | | view_name, |
| | | subpath, traversed, root, vroot, vroot_path) |
| | | ) |
| | | logger and logger.debug(msg) |
| | | else: |
| | | msg = request.path_info |
| | | raise HTTPNotFound(msg) |
| | | else: |
| | | result = view_callable(context, request) |
| | | |
| | | # handle exceptions raised during root finding and view-exec |
| | | except Exception, why: |
| | | attrs['exception'] = why |
| | | |
| | | for_ = (IExceptionViewClassifier, |
| | | request_iface.combined, |
| | | providedBy(why)) |
| | | view_callable = adapters.lookup(for_, IView, default=None) |
| | | |
| | | if view_callable is None: |
| | | raise |
| | | |
| | | result = view_callable(why, request) |
| | | |
| | | # process the response |
| | | response = registry.queryAdapterOrSelf(result, IResponse) |
| | | if response is None: |
| | | raise ValueError( |
| | | 'Could not convert view return value "%s" into a ' |
| | | 'response object' % (result,)) |
| | | |
| | | try: |
| | | response = self.handle_request(request) |
| | | has_listeners and notify(NewResponse(request, response)) |
| | | |
| | | if request.response_callbacks: |
| | | request._process_response_callbacks(response) |
| | | |
| | | return response(request.environ, start_response) |
| | | |
| | | finally: |
| | | if request is not None and request.finished_callbacks: |
| | | if request.finished_callbacks: |
| | | request._process_finished_callbacks() |
| | | |
| | | return response(request.environ, start_response) |
| | | |
| | | finally: |
| | | manager.pop() |
| | |
| | | try: |
| | | populate() |
| | | except IntegrityError: |
| | | DBSession.rollback() |
| | | transaction.abort() |
| | | return DBSession |
| | | |
| | | def appmaker(engine): |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | |
| | | sqlalchemy.url = sqlite:///%(here)s/{{project}}.db |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | tm |
| | | {{project}} |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.includes = pyramid_tm |
| | | |
| | | sqlalchemy.url = sqlite:///%(here)s/{{project}}.db |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | tm |
| | | {{project}} |
| | | |
| | | [server:main] |
| | |
| | | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'sqlalchemy', |
| | | 'zope.sqlalchemy', |
| | | 'WebError', |
| | |
| | | try: |
| | | populate() |
| | | except IntegrityError: |
| | | DBSession.rollback() |
| | | transaction.abort() |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | |
| | | sqlalchemy.url = sqlite:///%(here)s/{{project}}.db |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | tm |
| | | {{project}} |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | |
| | | sqlalchemy.url = sqlite:///%(here)s/{{project}}.db |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | tm |
| | | {{project}} |
| | | |
| | | [server:main] |
| | |
| | | 'pyramid', |
| | | 'SQLAlchemy', |
| | | 'transaction', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'zope.sqlalchemy', |
| | | 'WebError', |
| | | ] |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | {{project}} |
| | | |
| | | [server:main] |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | |
| | | [filter:weberror] |
| | | use = egg:WebError#error_catcher |
| | |
| | | README = open(os.path.join(here, 'README.txt')).read() |
| | | CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() |
| | | |
| | | requires = ['pyramid', 'WebError'] |
| | | requires = ['pyramid', 'pyramid_debugtoolbar', 'WebError'] |
| | | |
| | | setup(name='{{project}}', |
| | | version='0.0', |
| | |
| | | [os.path.join(self.directory, 'bin', 'python'), |
| | | 'setup.py', 'develop']) |
| | | os.chdir(self.directory) |
| | | |
| | | subprocess.check_call(['bin/paster', 'create', '-t', tmpl_name, |
| | | 'Dingle']) |
| | | os.chdir('Dingle') |
| | |
| | | subprocess.check_call([py, 'setup.py', 'install']) |
| | | subprocess.check_call([py, 'setup.py', 'test']) |
| | | paster = os.path.join(self.directory, 'bin', 'paster') |
| | | proc = subprocess.Popen([paster, 'serve', 'development.ini']) |
| | | try: |
| | | time.sleep(5) |
| | | proc.poll() |
| | | if proc.returncode is not None: |
| | | raise RuntimeError('didnt start') |
| | | conn = httplib.HTTPConnection('localhost:6543') |
| | | conn.request('GET', '/') |
| | | resp = conn.getresponse() |
| | | assert(resp.status == 200) |
| | | finally: |
| | | if hasattr(proc, 'terminate'): |
| | | # 2.6+ |
| | | proc.terminate() |
| | | else: |
| | | # 2.5 |
| | | os.kill(proc.pid, signal.SIGTERM) |
| | | for ininame, hastoolbar in (('development.ini', True), |
| | | ('production.ini', False)): |
| | | proc = subprocess.Popen([paster, 'serve', ininame]) |
| | | try: |
| | | time.sleep(5) |
| | | proc.poll() |
| | | if proc.returncode is not None: |
| | | raise RuntimeError('%s didnt start' % ininame) |
| | | conn = httplib.HTTPConnection('localhost:6543') |
| | | conn.request('GET', '/') |
| | | resp = conn.getresponse() |
| | | assert resp.status == 200, ininame |
| | | data = resp.read() |
| | | toolbarchunk = '<div id="flDebug"' |
| | | if hastoolbar: |
| | | assert toolbarchunk in data, ininame |
| | | else: |
| | | assert not toolbarchunk in data, ininame |
| | | finally: |
| | | if hasattr(proc, 'terminate'): |
| | | # 2.6+ |
| | | proc.terminate() |
| | | else: |
| | | # 2.5 |
| | | os.kill(proc.pid, signal.SIGTERM) |
| | | finally: |
| | | shutil.rmtree(self.directory) |
| | | os.chdir(self.old_cwd) |
| | |
| | | h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;} |
| | | html,body{width:100%;height:100%;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;} |
| | | a{color:#1b61d6;text-decoration:none;} |
| | | a:hover{color:#e88f00;text-decoration:underline;} |
| | | body h1, |
| | |
| | | <meta name="description" content="pyramid web application" /> |
| | | <link rel="shortcut icon" href="${request.static_url('{{package}}:static/favicon.ico')}" /> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen"> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" /> |
| | | <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" /> |
| | | <!--[if lte IE 6]> |
| | | <link rel="stylesheet" href="${request.static_url('{{package}}:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" /> |
| | | <![endif]--> |
| | |
| | | <div class="bottom"> |
| | | <div id="left" class="align-right"> |
| | | <h2>Search documentation</h2> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html"> |
| | | <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html"> |
| | | <input type="text" id="q" name="q" value="" /> |
| | | <input type="submit" id="x" value="Go" /> |
| | | </form> |
| | |
| | | <a href="http://pylonsproject.org">Pylons Website</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">Narrative Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">API Documentation</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">Tutorials</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">Change History</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">Sample Applications</a> |
| | | </li> |
| | | <li> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a> |
| | | <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">Support and Development</a> |
| | | </li> |
| | | <li> |
| | | <a href="irc://irc.freenode.net#pyramid">IRC Channel</a> |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = true |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = true |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = true |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = true |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_debugtoolbar |
| | | pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | egg:WebError#evalerror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | {{project}} |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [server:main] |
| | | use = egg:Paste#http |
| | |
| | | [app:{{project}}] |
| | | use = egg:{{project}} |
| | | reload_templates = false |
| | | debug_authorization = false |
| | | debug_notfound = false |
| | | debug_routematch = false |
| | | debug_templates = false |
| | | default_locale_name = en |
| | | |
| | | pyramid.reload_templates = false |
| | | pyramid.debug_authorization = false |
| | | pyramid.debug_notfound = false |
| | | pyramid.debug_routematch = false |
| | | pyramid.debug_templates = false |
| | | pyramid.default_locale_name = en |
| | | pyramid.include = pyramid_tm |
| | | pyramid_tm.attempts = 3 |
| | | |
| | | zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000 |
| | | |
| | | [filter:weberror] |
| | |
| | | ;smtp_use_tls = |
| | | ;error_message = |
| | | |
| | | [filter:tm] |
| | | use = egg:repoze.tm2#tm |
| | | commit_veto = repoze.tm:default_commit_veto |
| | | |
| | | [pipeline:main] |
| | | pipeline = |
| | | weberror |
| | | egg:repoze.zodbconn#closer |
| | | egg:repoze.retry#retry |
| | | tm |
| | | {{project}} |
| | | |
| | | [server:main] |
| | |
| | | requires = [ |
| | | 'pyramid', |
| | | 'repoze.zodbconn', |
| | | 'repoze.tm2>=1.0b1', # default_commit_veto |
| | | 'repoze.retry', |
| | | 'pyramid_tm', |
| | | 'pyramid_debugtoolbar', |
| | | 'ZODB3', |
| | | 'WebError', |
| | | ] |
| | |
| | | from pyramid.config import global_registries |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.request import Request |
| | | from pyramid.interfaces import IRequestFactory |
| | | from pyramid.interfaces import IRootFactory |
| | | from pyramid.threadlocal import manager as threadlocal_manager |
| | | from pyramid.traversal import DefaultRootFactory |
| | | |
| | | def get_root(app, request=None): |
| | | """ Return a tuple composed of ``(root, closer)`` when provided a |
| | | :term:`router` instance as the ``app`` argument. The ``root`` |
| | | returned is the application root object. The ``closer`` returned |
| | | is a callable (accepting no arguments) that should be called when |
| | | your scripting application is finished using the root. If |
| | | ``request`` is not None, it is used as the request passed to the |
| | | :app:`Pyramid` application root factory. A request is |
| | | constructed and passed to the root factory if ``request`` is None.""" |
| | | your scripting application is finished using the root. |
| | | |
| | | ``request`` is passed to the :app:`Pyramid` application root |
| | | factory to compute the root. If ``request`` is None, a default |
| | | will be constructed using the registry's :term:`Request Factory` |
| | | via the :meth:`pyramid.interfaces.IRequestFactory.blank` method. |
| | | """ |
| | | registry = app.registry |
| | | if request is None: |
| | | request_factory = registry.queryUtility( |
| | | IRequestFactory, default=Request) |
| | | request = request_factory.blank('/') |
| | | request.registry = registry |
| | | request = _make_request('/', registry) |
| | | threadlocals = {'registry':registry, 'request':request} |
| | | app.threadlocal_manager.push(threadlocals) |
| | | def closer(request=request): # keep request alive via this function default |
| | |
| | | root = app.root_factory(request) |
| | | return root, closer |
| | | |
| | | def prepare(request=None, registry=None): |
| | | """ This function pushes data onto the Pyramid threadlocal stack |
| | | (request and registry), making those objects 'current'. It |
| | | returns a dictionary useful for bootstrapping a Pyramid |
| | | application in a scripting environment. |
| | | |
| | | ``request`` is passed to the :app:`Pyramid` application root |
| | | factory to compute the root. If ``request`` is None, a default |
| | | will be constructed using the registry's :term:`Request Factory` |
| | | via the :meth:`pyramid.interfaces.IRequestFactory.blank` method. |
| | | |
| | | If ``registry`` is not supplied, the last registry loaded from |
| | | :attr:`pyramid.config.global_registries` will be used. If you |
| | | have loaded more than one :app:`Pyramid` application in the |
| | | current process, you may not want to use the last registry |
| | | loaded, thus you can search the ``global_registries`` and supply |
| | | the appropriate one based on your own criteria. |
| | | |
| | | The function returns a dictionary composed of ``root``, |
| | | ``closer``, ``registry``, ``request`` and ``root_factory``. The |
| | | ``root`` returned is the application's root resource object. The |
| | | ``closer`` returned is a callable (accepting no arguments) that |
| | | should be called when your scripting application is finished |
| | | using the root. ``registry`` is the registry object passed or |
| | | the last registry loaded into |
| | | :attr:`pyramid.config.global_registries` if no registry is passed. |
| | | ``request`` is the request object passed or the constructed request |
| | | if no request is passed. ``root_factory`` is the root factory used |
| | | to construct the root. |
| | | """ |
| | | if registry is None: |
| | | registry = getattr(request, 'registry', global_registries.last) |
| | | if registry is None: |
| | | raise ConfigurationError('No valid Pyramid applications could be ' |
| | | 'found, make sure one has been created ' |
| | | 'before trying to activate it.') |
| | | if request is None: |
| | | request = _make_request('/', registry) |
| | | request.registry = registry |
| | | threadlocals = {'registry':registry, 'request':request} |
| | | threadlocal_manager.push(threadlocals) |
| | | def closer(): |
| | | threadlocal_manager.pop() |
| | | root_factory = registry.queryUtility(IRootFactory, |
| | | default=DefaultRootFactory) |
| | | root = root_factory(request) |
| | | return {'root':root, 'closer':closer, 'registry':registry, |
| | | 'request':request, 'root_factory':root_factory} |
| | | |
| | | def _make_request(path, registry=None): |
| | | """ Return a :meth:`pyramid.request.Request` object anchored at a |
| | | given path. The object returned will be generated from the supplied |
| | | registry's :term:`Request Factory` using the |
| | | :meth:`pyramid.interfaces.IRequestFactory.blank` method. |
| | | |
| | | This request object can be passed to :meth:`pyramid.scripting.get_root` |
| | | or :meth:`pyramid.scripting.prepare` to initialize an application in |
| | | preparation for executing a script with a proper environment setup. |
| | | URLs can then be generated with the object, as well as rendering |
| | | templates. |
| | | |
| | | If ``registry`` is not supplied, the last registry loaded from |
| | | :attr:`pyramid.config.global_registries` will be used. If you have |
| | | loaded more than one :app:`Pyramid` application in the current |
| | | process, you may not want to use the last registry loaded, thus |
| | | you can search the ``global_registries`` and supply the appropriate |
| | | one based on your own criteria. |
| | | """ |
| | | if registry is None: |
| | | registry = global_registries.last |
| | | request_factory = registry.queryUtility(IRequestFactory, default=Request) |
| | | request = request_factory.blank(path) |
| | | request.registry = registry |
| | | return request |
| | |
| | | ALL_PERMISSIONS = AllPermissionsList() |
| | | DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS) |
| | | |
| | | NO_PERMISSION_REQUIRED = '__no_permission_required__' |
| | | |
| | | def has_permission(permission, context, request): |
| | | """ Provided a permission (a string or unicode object), a context |
| | | (a :term:`resource` instance) and a request object, return an |
| | |
| | | dict.__init__(self, d, **kw) |
| | | eget = _environ_.get |
| | | config_debug_all = self.get('debug_all', '') |
| | | config_debug_all = self.get('pyramid.debug_all', config_debug_all) |
| | | eff_debug_all = asbool(eget('PYRAMID_DEBUG_ALL', config_debug_all)) |
| | | config_reload_all = self.get('reload_all', '') |
| | | eff_reload_all = asbool(eget('PYRAMID_RELOAD_ALL',config_reload_all)) |
| | | config_reload_all = self.get('pyramid.reload_all', config_reload_all) |
| | | eff_reload_all = asbool(eget('PYRAMID_RELOAD_ALL', config_reload_all)) |
| | | config_debug_auth = self.get('debug_authorization', '') |
| | | config_debug_auth = self.get('pyramid.debug_authorization', |
| | | config_debug_auth) |
| | | eff_debug_auth = asbool(eget('PYRAMID_DEBUG_AUTHORIZATION', |
| | | config_debug_auth)) |
| | | config_debug_notfound = self.get('debug_notfound', '') |
| | | config_debug_notfound = self.get('pyramid.debug_notfound', |
| | | config_debug_notfound) |
| | | eff_debug_notfound = asbool(eget('PYRAMID_DEBUG_NOTFOUND', |
| | | config_debug_notfound)) |
| | | config_debug_routematch = self.get('debug_routematch', '') |
| | | config_debug_routematch = self.get('pyramid.debug_routematch', |
| | | config_debug_routematch) |
| | | eff_debug_routematch = asbool(eget('PYRAMID_DEBUG_ROUTEMATCH', |
| | | config_debug_routematch)) |
| | | config_debug_templates = self.get('debug_templates', '') |
| | | config_debug_templates = self.get('pyramid.debug_templates', |
| | | config_debug_templates) |
| | | eff_debug_templates = asbool(eget('PYRAMID_DEBUG_TEMPLATES', |
| | | config_debug_templates)) |
| | | config_reload_templates = self.get('reload_templates', '') |
| | | config_reload_templates = self.get('pyramid.reload_templates', |
| | | config_reload_templates) |
| | | eff_reload_templates = asbool(eget('PYRAMID_RELOAD_TEMPLATES', |
| | | config_reload_templates)) |
| | | config_reload_assets = self.get('reload_assets', '') |
| | | config_reload_resources = self.get('reload_resources', '') |
| | | config_reload_assets = self.get('pyramid.reload_assets', |
| | | config_reload_assets) |
| | | reload_assets = asbool(eget('PYRAMID_RELOAD_ASSETS', |
| | | config_reload_assets)) |
| | | config_reload_resources = self.get('reload_resources', '') |
| | | config_reload_resources = self.get('pyramid.reload_resources', |
| | | config_reload_resources) |
| | | reload_resources = asbool(eget('PYRAMID_RELOAD_RESOURCES', |
| | | config_reload_resources)) |
| | | # reload_resources is an older alias for reload_assets |
| | | eff_reload_assets = reload_assets or reload_resources |
| | | locale_name = self.get('default_locale_name', 'en') |
| | | locale_name = self.get('pyramid.default_locale_name', locale_name) |
| | | eff_locale_name = eget('PYRAMID_DEFAULT_LOCALE_NAME', locale_name) |
| | | |
| | | config_prevent_http_cache = self.get('prevent_http_cache', '') |
| | | config_prevent_http_cache = self.get('pyramid.prevent_http_cache', |
| | | config_prevent_http_cache) |
| | | eff_prevent_http_cache = asbool(eget('PYRAMID_PREVENT_HTTP_CACHE', |
| | | config_prevent_http_cache)) |
| | | |
| | | update = { |
| | | 'debug_authorization': eff_debug_all or eff_debug_auth, |
| | | 'debug_notfound': eff_debug_all or eff_debug_notfound, |
| | |
| | | 'reload_resources':eff_reload_all or eff_reload_assets, |
| | | 'reload_assets':eff_reload_all or eff_reload_assets, |
| | | 'default_locale_name':eff_locale_name, |
| | | 'prevent_http_cache':eff_prevent_http_cache, |
| | | |
| | | 'pyramid.debug_authorization': eff_debug_all or eff_debug_auth, |
| | | 'pyramid.debug_notfound': eff_debug_all or eff_debug_notfound, |
| | | 'pyramid.debug_routematch': eff_debug_all or eff_debug_routematch, |
| | | 'pyramid.debug_templates': eff_debug_all or eff_debug_templates, |
| | | 'pyramid.reload_templates': eff_reload_all or eff_reload_templates, |
| | | 'pyramid.reload_resources':eff_reload_all or eff_reload_assets, |
| | | 'pyramid.reload_assets':eff_reload_all or eff_reload_assets, |
| | | 'pyramid.default_locale_name':eff_locale_name, |
| | | 'pyramid.prevent_http_cache':eff_prevent_http_cache, |
| | | } |
| | | |
| | | self.update(update) |
| | |
| | | from pyramid.interfaces import IStaticURLInfo |
| | | from pyramid.path import caller_package |
| | | from pyramid.request import call_app_with_subpath_as_path_info |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | from pyramid.url import route_url |
| | | |
| | | class PackageURLParser(StaticURLParser): |
| | |
| | | # it's a view name |
| | | cache_max_age = extra.pop('cache_max_age', None) |
| | | # create a view |
| | | view = static_view(spec, cache_max_age=cache_max_age) |
| | | view = static_view(spec, cache_max_age=cache_max_age, |
| | | use_subpath=True) |
| | | |
| | | # Mutate extra to allow factory, etc to be passed through here. |
| | | # Treat permission specially because we'd like to default to |
| | |
| | | if permission is None: |
| | | permission = extra.pop('permission', None) |
| | | if permission is None: |
| | | permission = '__no_permission_required__' |
| | | permission = NO_PERMISSION_REQUIRED |
| | | |
| | | context = extra.pop('view_context', None) |
| | | if context is None: |
| | |
| | | response headers returned by the view (default is 3600 seconds or |
| | | five minutes). |
| | | |
| | | ``use_subpath`` influences whether ``request.subpath`` will be used as |
| | | ``PATH_INFO`` when calling the underlying WSGI application which actually |
| | | serves the static files. If it is ``True``, the static application will |
| | | consider ``request.subpath`` as ``PATH_INFO`` input. If it is ``False``, |
| | | the static application will consider request.path_info as ``PATH_INFO`` |
| | | input. By default, this is ``False``. |
| | | |
| | | .. note:: If the ``root_dir`` is relative to a :term:`package`, or |
| | | is a :term:`asset specification` the :app:`Pyramid` |
| | | :class:`pyramid.config.Configurator` method can be |
| | |
| | | absolute, configuration will not be able to |
| | | override the assets it contains. """ |
| | | |
| | | def __init__(self, root_dir, cache_max_age=3600, package_name=None): |
| | | def __init__(self, root_dir, cache_max_age=3600, package_name=None, |
| | | use_subpath=False): |
| | | # package_name is for bw compat; it is preferred to pass in a |
| | | # package-relative path as root_dir |
| | | # (e.g. ``anotherpackage:foo/static``). |
| | |
| | | app = PackageURLParser( |
| | | package_name, root_dir, cache_max_age=cache_max_age) |
| | | self.app = app |
| | | self.use_subpath = use_subpath |
| | | |
| | | def __call__(self, context, request): |
| | | return call_app_with_subpath_as_path_info(request, self.app) |
| | | if self.use_subpath: |
| | | return call_app_with_subpath_as_path_info(request, self.app) |
| | | return request.get_response(self.app) |
| | |
| | | from webob import Response |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config(name='x') |
| | |
| | | def y_view(request): # pragma: no cover |
| | | return Response('this is private too!') |
| | | |
| | | @view_config(name='z', permission='__no_permission_required__') |
| | | @view_config(name='z', permission=NO_PERMISSION_REQUIRED) |
| | | def z_view(request): |
| | | return Response('this is public') |
| | | |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | @view_config() |
| | | @view_config(renderer=null_renderer) |
| | | def grokked(context, request): |
| | | return 'grokked' |
| | | |
| | | @view_config(request_method='POST') |
| | | @view_config(request_method='POST', renderer=null_renderer) |
| | | def grokked_post(context, request): |
| | | return 'grokked_post' |
| | | |
| | | @view_config(name='stacked2') |
| | | @view_config(name='stacked1') |
| | | @view_config(name='stacked2', renderer=null_renderer) |
| | | @view_config(name='stacked1', renderer=null_renderer) |
| | | def stacked(context, request): |
| | | return 'stacked' |
| | | |
| | |
| | | def __call__(self): |
| | | return 'stacked_class' |
| | | |
| | | stacked_class = view_config(name='stacked_class1')(stacked_class) |
| | | stacked_class = view_config(name='stacked_class2')(stacked_class) |
| | | stacked_class = view_config(name='stacked_class1', |
| | | renderer=null_renderer)(stacked_class) |
| | | stacked_class = view_config(name='stacked_class2', |
| | | renderer=null_renderer)(stacked_class) |
| | | |
| | | class oldstyle_grokked_class: |
| | | def __init__(self, context, request): |
| | |
| | | def __call__(self): |
| | | return 'oldstyle_grokked_class' |
| | | |
| | | oldstyle_grokked_class = view_config(name='oldstyle_grokked_class')( |
| | | oldstyle_grokked_class = view_config(name='oldstyle_grokked_class', |
| | | renderer=null_renderer)( |
| | | oldstyle_grokked_class) |
| | | |
| | | class grokked_class(object): |
| | |
| | | def __call__(self): |
| | | return 'grokked_class' |
| | | |
| | | grokked_class = view_config(name='grokked_class')(grokked_class) |
| | | grokked_class = view_config(name='grokked_class', |
| | | renderer=null_renderer)(grokked_class) |
| | | |
| | | class Foo(object): |
| | | def __call__(self, context, request): |
| | | return 'grokked_instance' |
| | | |
| | | grokked_instance = Foo() |
| | | grokked_instance = view_config(name='grokked_instance')(grokked_instance) |
| | | grokked_instance = view_config(name='grokked_instance', |
| | | renderer=null_renderer)(grokked_instance) |
| | | |
| | | class Base(object): |
| | | @view_config(name='basemethod') |
| | | @view_config(name='basemethod', renderer=null_renderer) |
| | | def basemethod(self): |
| | | """ """ |
| | | |
| | |
| | | self.context = context |
| | | self.request = request |
| | | |
| | | @view_config(name='method1') |
| | | @view_config(name='method1', renderer=null_renderer) |
| | | def method1(self): |
| | | return 'method1' |
| | | |
| | | @view_config(name='method2') |
| | | @view_config(name='method2', renderer=null_renderer) |
| | | def method2(self): |
| | | return 'method2' |
| | | |
| | | @view_config(name='stacked_method2') |
| | | @view_config(name='stacked_method1') |
| | | @view_config(name='stacked_method2', renderer=null_renderer) |
| | | @view_config(name='stacked_method1', renderer=null_renderer) |
| | | def stacked(self): |
| | | return 'stacked_method' |
| | | |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | @view_config(name='another') |
| | | @view_config(name='another', renderer=null_renderer) |
| | | def grokked(context, request): |
| | | return 'another_grokked' |
| | | |
| | | @view_config(request_method='POST', name='another') |
| | | @view_config(request_method='POST', name='another', renderer=null_renderer) |
| | | def grokked_post(context, request): |
| | | return 'another_grokked_post' |
| | | |
| | | @view_config(name='another_stacked2') |
| | | @view_config(name='another_stacked1') |
| | | @view_config(name='another_stacked2', renderer=null_renderer) |
| | | @view_config(name='another_stacked1', renderer=null_renderer) |
| | | def stacked(context, request): |
| | | return 'another_stacked' |
| | | |
| | |
| | | def __call__(self): |
| | | return 'another_stacked_class' |
| | | |
| | | stacked_class = view_config(name='another_stacked_class1')(stacked_class) |
| | | stacked_class = view_config(name='another_stacked_class2')(stacked_class) |
| | | stacked_class = view_config(name='another_stacked_class1', |
| | | renderer=null_renderer)(stacked_class) |
| | | stacked_class = view_config(name='another_stacked_class2', |
| | | renderer=null_renderer)(stacked_class) |
| | | |
| | | class oldstyle_grokked_class: |
| | | def __init__(self, context, request): |
| | |
| | | def __call__(self): |
| | | return 'another_oldstyle_grokked_class' |
| | | |
| | | oldstyle_grokked_class = view_config(name='another_oldstyle_grokked_class')( |
| | | oldstyle_grokked_class = view_config(name='another_oldstyle_grokked_class', |
| | | renderer=null_renderer)( |
| | | oldstyle_grokked_class) |
| | | |
| | | class grokked_class(object): |
| | |
| | | def __call__(self): |
| | | return 'another_grokked_class' |
| | | |
| | | grokked_class = view_config(name='another_grokked_class')(grokked_class) |
| | | grokked_class = view_config(name='another_grokked_class', |
| | | renderer=null_renderer)(grokked_class) |
| | | |
| | | class Foo(object): |
| | | def __call__(self, context, request): |
| | | return 'another_grokked_instance' |
| | | |
| | | grokked_instance = Foo() |
| | | grokked_instance = view_config(name='another_grokked_instance')( |
| | | grokked_instance = view_config(name='another_grokked_instance', |
| | | renderer=null_renderer)( |
| | | grokked_instance) |
| | | |
| | | # ungrokkable |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | @view_config(name='pod_notinit') |
| | | @view_config(name='pod_notinit', renderer=null_renderer) |
| | | def subpackage_notinit(context, request): |
| | | return 'pod_notinit' |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | @view_config(name='subpackage_init') |
| | | @view_config(name='subpackage_init', renderer=null_renderer) |
| | | def subpackage_init(context, request): |
| | | return 'subpackage_init' |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | @view_config(name='subpackage_notinit') |
| | | @view_config(name='subpackage_notinit', renderer=null_renderer) |
| | | def subpackage_notinit(context, request): |
| | | return 'subpackage_notinit' |
| | |
| | | from pyramid.view import view_config |
| | | from pyramid.renderers import null_renderer |
| | | |
| | | @view_config(name='subsubpackage_init') |
| | | @view_config(name='subsubpackage_init', renderer=null_renderer) |
| | | def subpackage_init(context, request): |
| | | return 'subsubpackage_init' |
| | |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | |
| | | class BaseRESTView(object): |
| | | def __init__(self, context, request): |
| | |
| | | class ConfiguratorTests(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | return Configurator(*arg, **kw) |
| | | config = Configurator(*arg, **kw) |
| | | return config |
| | | |
| | | def _registerRenderer(self, config, name='.txt'): |
| | | from pyramid.interfaces import IRendererFactory |
| | |
| | | from pyramid.interfaces import IDebugLogger |
| | | config = self._makeOne() |
| | | logger = config.registry.getUtility(IDebugLogger) |
| | | self.assertEqual(logger.name, 'pyramid.debug') |
| | | self.assertEqual(logger.name, 'pyramid.tests') |
| | | |
| | | def test_ctor_noreg_debug_logger_non_None(self): |
| | | from pyramid.interfaces import IDebugLogger |
| | |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=IExceptionResponse, |
| | | request_iface=IRequest) |
| | | self.assertTrue(view is default_exceptionresponse_view) |
| | | self.assertTrue(view.__wraps__ is default_exceptionresponse_view) |
| | | |
| | | def test_ctor_exceptionresponse_view_None(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=IExceptionResponse, |
| | | request_iface=IRequest) |
| | | self.assertTrue(view is exceptionresponse_view) |
| | | self.assertTrue(view.__wraps__ is exceptionresponse_view) |
| | | |
| | | def test_with_package_module(self): |
| | | from pyramid.tests import test_configuration |
| | |
| | | reg = DummyRegistry() |
| | | config = self._makeOne(reg) |
| | | config.add_view = lambda *arg, **kw: False |
| | | config._add_tween = lambda *arg, **kw: False |
| | | config.setup_registry() |
| | | self.assertEqual(reg.has_listeners, True) |
| | | |
| | |
| | | config = self._makeOne(reg) |
| | | views = [] |
| | | config.add_view = lambda *arg, **kw: views.append((arg, kw)) |
| | | config._add_tween = lambda *arg, **kw: False |
| | | config.setup_registry() |
| | | self.assertEqual(views[0], ((default_exceptionresponse_view,), |
| | | {'context':IExceptionResponse})) |
| | |
| | | config.registry.queryAdapter(response, IResponse) is response) |
| | | |
| | | def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | |
| | | config.setup_registry() # registers IExceptionResponse default view |
| | | def myview(context, request): |
| | | return 'OK' |
| | | config.add_view(myview, context=HTTPNotFound) |
| | | config.add_view(myview, context=HTTPNotFound, renderer=null_renderer) |
| | | request = self._makeRequest(config) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPNotFound), |
| | |
| | | config = self._makeOne(reg) |
| | | config.setup_registry() |
| | | logger = reg.getUtility(IDebugLogger) |
| | | self.assertEqual(logger.name, 'pyramid.debug') |
| | | self.assertEqual(logger.name, 'pyramid.tests') |
| | | |
| | | def test_setup_registry_debug_logger_non_None(self): |
| | | from pyramid.registry import Registry |
| | |
| | | result = reg.getUtility(IDebugLogger) |
| | | self.assertEqual(logger, result) |
| | | |
| | | def test_setup_registry_debug_logger_dottedname(self): |
| | | def test_setup_registry_debug_logger_name(self): |
| | | from pyramid.registry import Registry |
| | | from pyramid.interfaces import IDebugLogger |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | config.setup_registry(debug_logger='pyramid.tests') |
| | | config.setup_registry(debug_logger='foo') |
| | | result = reg.getUtility(IDebugLogger) |
| | | import pyramid.tests |
| | | self.assertEqual(result, pyramid.tests) |
| | | self.assertEqual(result.name, 'foo') |
| | | |
| | | def test_setup_registry_authentication_policy(self): |
| | | from pyramid.registry import Registry |
| | |
| | | config.setup_registry(default_permission='view') |
| | | self.assertEqual(reg.getUtility(IDefaultPermission), 'view') |
| | | |
| | | def test_setup_registry_includes(self): |
| | | from pyramid.registry import Registry |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | settings = { |
| | | 'pyramid.include': """pyramid.tests.test_config.dummy_include |
| | | pyramid.tests.test_config.dummy_include2""", |
| | | } |
| | | config.setup_registry(settings=settings) |
| | | self.assert_(reg.included) |
| | | self.assert_(reg.also_included) |
| | | |
| | | def test_setup_registry_tweens(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.registry import Registry |
| | | reg = Registry() |
| | | config = self._makeOne(reg) |
| | | settings = { |
| | | 'pyramid.tweens': 'pyramid.tests.test_config.dummy_tween_factory' |
| | | } |
| | | config.setup_registry(settings=settings) |
| | | config.commit() |
| | | tweens = config.registry.getUtility(ITweens) |
| | | self.assertEqual(tweens.explicit, |
| | | [('pyramid.tests.test_config.dummy_tween_factory', |
| | | dummy_tween_factory)]) |
| | | |
| | | def test_get_settings_nosettings(self): |
| | | from pyramid.registry import Registry |
| | | reg = Registry() |
| | |
| | | config.add_settings({'a':1}) |
| | | settings = reg.getUtility(ISettings) |
| | | self.assertEqual(settings['a'], 1) |
| | | |
| | | def test_add_tweens_names_distinct(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.tweens import excview_tween_factory |
| | | def factory1(handler, registry): return handler |
| | | def factory2(handler, registry): return handler |
| | | config = self._makeOne() |
| | | config.add_tween(factory1) |
| | | config.add_tween(factory2) |
| | | config.commit() |
| | | tweens = config.registry.queryUtility(ITweens) |
| | | implicit = tweens.implicit() |
| | | self.assertEqual( |
| | | implicit, |
| | | [ |
| | | ('pyramid.tests.test_config.factory2', factory2), |
| | | ('pyramid.tests.test_config.factory1', factory1), |
| | | ('pyramid.tweens.excview_tween_factory', excview_tween_factory), |
| | | ] |
| | | ) |
| | | |
| | | def test_add_tweens_names_with_underover(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.tweens import excview_tween_factory |
| | | from pyramid.tweens import MAIN |
| | | def factory1(handler, registry): return handler |
| | | def factory2(handler, registry): return handler |
| | | config = self._makeOne() |
| | | config.add_tween(factory1, over=MAIN) |
| | | config.add_tween(factory2, over=MAIN, |
| | | under='pyramid.tests.test_config.factory1') |
| | | config.commit() |
| | | tweens = config.registry.queryUtility(ITweens) |
| | | implicit = tweens.implicit() |
| | | self.assertEqual( |
| | | implicit, |
| | | [ |
| | | ('pyramid.tweens.excview_tween_factory', excview_tween_factory), |
| | | ('pyramid.tests.test_config.factory1', factory1), |
| | | ('pyramid.tests.test_config.factory2', factory2), |
| | | ]) |
| | | |
| | | def test_add_tween_dottedname(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.tweens import excview_tween_factory |
| | | config = self._makeOne() |
| | | config.add_tween('pyramid.tests.test_config.dummy_tween_factory') |
| | | config.commit() |
| | | tweens = config.registry.queryUtility(ITweens) |
| | | self.assertEqual( |
| | | tweens.implicit(), |
| | | [ |
| | | ('pyramid.tests.test_config.dummy_tween_factory', |
| | | dummy_tween_factory), |
| | | ('pyramid.tweens.excview_tween_factory', excview_tween_factory), |
| | | ]) |
| | | |
| | | def test_add_tween_instance(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.tweens import excview_tween_factory |
| | | class ATween(object): pass |
| | | atween = ATween() |
| | | config = self._makeOne() |
| | | config.add_tween(atween) |
| | | config.commit() |
| | | tweens = config.registry.queryUtility(ITweens) |
| | | implicit = tweens.implicit() |
| | | self.assertEqual(len(implicit), 2) |
| | | self.assertTrue( |
| | | implicit[0][0].startswith( |
| | | 'pyramid.tests.test_config.ATween.')) |
| | | self.assertEqual(implicit[0][1], atween) |
| | | self.assertEqual( |
| | | implicit[1], |
| | | ('pyramid.tweens.excview_tween_factory', excview_tween_factory)) |
| | | |
| | | def test_add_tween_unsuitable(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | import pyramid.tests |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, config.add_tween, pyramid.tests) |
| | | |
| | | def test_add_tween_alias_ingress(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.tweens import INGRESS |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, |
| | | config.add_tween, 'pyramid.tests.test_config.dummy_tween_factory', |
| | | alias=INGRESS) |
| | | |
| | | def test_add_tween_alias_main(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.tweens import MAIN |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, |
| | | config.add_tween, 'pyramid.tests.test_config.dummy_tween_factory', |
| | | alias=MAIN) |
| | | |
| | | def test_add_tweens_conflict(self): |
| | | from zope.configuration.config import ConfigurationConflictError |
| | | config = self._makeOne() |
| | | config.add_tween('pyramid.tests.test_config.dummy_tween_factory') |
| | | config.add_tween('pyramid.tests.test_config.dummy_tween_factory') |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | | |
| | | def test_add_tweens_conflict_same_alias(self): |
| | | from zope.configuration.config import ConfigurationConflictError |
| | | class ATween(object): pass |
| | | atween1 = ATween() |
| | | atween2 = ATween() |
| | | config = self._makeOne() |
| | | config.add_tween(atween1, alias='a') |
| | | config.add_tween(atween2, alias='a') |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | | |
| | | def test_add_tween_over_ingress(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.tweens import INGRESS |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, |
| | | config.add_tween, 'pyramid.tests.test_config.dummy_tween_factory', |
| | | over=INGRESS) |
| | | |
| | | def test_add_tween_under_main(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.tweens import MAIN |
| | | config = self._makeOne() |
| | | self.assertRaises(ConfigurationError, |
| | | config.add_tween, 'pyramid.tests.test_config.dummy_tween_factory', |
| | | under=MAIN) |
| | | |
| | | def test_add_subscriber_defaults(self): |
| | | from zope.interface import implements |
| | |
| | | self.assertEqual(len(L), 1) |
| | | |
| | | def test_make_wsgi_app(self): |
| | | import pyramid.config |
| | | from pyramid.router import Router |
| | | from pyramid.interfaces import IApplicationCreated |
| | | manager = DummyThreadLocalManager() |
| | |
| | | self.assertEqual(manager.pushed['registry'], config.registry) |
| | | self.assertEqual(manager.pushed['request'], None) |
| | | self.assertTrue(manager.popped) |
| | | self.assertEqual(pyramid.config.global_registries.last, app.registry) |
| | | self.assertEqual(len(subscriber), 1) |
| | | self.assertTrue(IApplicationCreated.providedBy(subscriber[0])) |
| | | pyramid.config.global_registries.empty() |
| | | |
| | | def test_global_registries_empty(self): |
| | | from pyramid.config import global_registries |
| | | self.assertEqual(global_registries.last, None) |
| | | |
| | | def test_global_registries(self): |
| | | from pyramid.config import global_registries |
| | | global_registries.empty() |
| | | config1 = self._makeOne() |
| | | config1.make_wsgi_app() |
| | | self.assertEqual(global_registries.last, config1.registry) |
| | | config2 = self._makeOne() |
| | | config2.make_wsgi_app() |
| | | self.assertEqual(global_registries.last, config2.registry) |
| | | self.assertEqual(list(global_registries), |
| | | [config1.registry, config2.registry]) |
| | | global_registries.remove(config2.registry) |
| | | self.assertEqual(global_registries.last, config1.registry) |
| | | global_registries.empty() |
| | | |
| | | def test_include_with_dotted_name(self): |
| | | from pyramid import tests |
| | |
| | | None, True, True) |
| | | |
| | | def test_add_view_with_request_type(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import directlyProvides |
| | | from pyramid.interfaces import IRequest |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, |
| | | request_type='pyramid.interfaces.IRequest') |
| | | request_type='pyramid.interfaces.IRequest', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = DummyRequest() |
| | | self._assertNotFound(wrapper, None, request) |
| | |
| | | self.assertEqual(wrapper.__doc__, view.__doc__) |
| | | |
| | | def test_add_view_view_callable_dottedname(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view='pyramid.tests.test_config.dummy_view') |
| | | config.add_view(view='pyramid.tests.test_config.dummy_view', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | | |
| | | def test_add_view_with_function_callable(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | result = wrapper(None, None) |
| | | self.assertEqual(result, 'OK') |
| | | |
| | | def test_add_view_with_function_callable_requestonly(self): |
| | | from pyramid.renderers import null_renderer |
| | | def view(request): |
| | | return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | result = wrapper(None, None) |
| | | self.assertEqual(result, 'OK') |
| | | |
| | | def test_add_view_with_decorator(self): |
| | | from pyramid.renderers import null_renderer |
| | | def view(request): |
| | | """ ABC """ |
| | | return 'OK' |
| | |
| | | return fn(context, request) |
| | | return inner |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, decorator=view_wrapper) |
| | | config.add_view(view=view, decorator=view_wrapper, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertFalse(wrapper is view) |
| | | self.assertEqual(wrapper.__doc__, view.__doc__) |
| | |
| | | assert_similar_datetime(expires, when) |
| | | |
| | | def test_add_view_as_instance(self): |
| | | from pyramid.renderers import null_renderer |
| | | class AView: |
| | | def __call__(self, context, request): |
| | | """ """ |
| | | return 'OK' |
| | | view = AView() |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | result = wrapper(None, None) |
| | | self.assertEqual(result, 'OK') |
| | | |
| | | def test_add_view_as_instance_requestonly(self): |
| | | from pyramid.renderers import null_renderer |
| | | class AView: |
| | | def __call__(self, request): |
| | | """ """ |
| | | return 'OK' |
| | | view = AView() |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | result = wrapper(None, None) |
| | | self.assertEqual(result, 'OK') |
| | | |
| | | def test_add_view_as_oldstyle_class(self): |
| | | from pyramid.renderers import null_renderer |
| | | class view: |
| | | def __init__(self, context, request): |
| | | self.context = context |
| | |
| | | def __call__(self): |
| | | return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | result = wrapper(None, request) |
| | |
| | | self.assertEqual(request.__view__.__class__, view) |
| | | |
| | | def test_add_view_as_oldstyle_class_requestonly(self): |
| | | from pyramid.renderers import null_renderer |
| | | class view: |
| | | def __init__(self, request): |
| | | self.request = request |
| | |
| | | def __call__(self): |
| | | return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | |
| | | request = self._makeRequest(config) |
| | |
| | | self.assertEqual(request.__view__.__class__, view) |
| | | |
| | | def test_add_view_context_as_class(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | view = lambda *arg: 'OK' |
| | | class Foo: |
| | | pass |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(context=Foo, view=view) |
| | | config.add_view(context=Foo, view=view, renderer=null_renderer) |
| | | foo = implementedBy(Foo) |
| | | wrapper = self._getViewCallable(config, foo) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_context_as_iface(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(context=IDummy, view=view) |
| | | config.add_view(context=IDummy, view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, IDummy) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_context_as_dottedname(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(context='pyramid.tests.test_config.IDummy', |
| | | view=view) |
| | | view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, IDummy) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_for__as_dottedname(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(for_='pyramid.tests.test_config.IDummy', |
| | | view=view) |
| | | view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, IDummy) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_for_as_class(self): |
| | | # ``for_`` is older spelling for ``context`` |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | view = lambda *arg: 'OK' |
| | | class Foo: |
| | | pass |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(for_=Foo, view=view) |
| | | config.add_view(for_=Foo, view=view, renderer=null_renderer) |
| | | foo = implementedBy(Foo) |
| | | wrapper = self._getViewCallable(config, foo) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_for_as_iface(self): |
| | | # ``for_`` is older spelling for ``context`` |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(for_=IDummy, view=view) |
| | | config.add_view(for_=IDummy, view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, IDummy) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_context_trumps_for(self): |
| | | # ``for_`` is older spelling for ``context`` |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | class Foo: |
| | | pass |
| | | config.add_view(context=IDummy, for_=Foo, view=view) |
| | | config.add_view(context=IDummy, for_=Foo, view=view, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, IDummy) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_register_secured_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import ISecuredView |
| | |
| | | view = lambda *arg: 'OK' |
| | | view.__call_permissive__ = view |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = config.registry.adapters.lookup( |
| | | (IViewClassifier, IRequest, Interface), |
| | | ISecuredView, name='', default=None) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_exception_register_secured_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view = lambda *arg: 'OK' |
| | | view.__call_permissive__ = view |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, context=RuntimeError) |
| | | config.add_view(view=view, context=RuntimeError, renderer=null_renderer) |
| | | wrapper = config.registry.adapters.lookup( |
| | | (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), |
| | | IView, name='', default=None) |
| | | self.assertEqual(wrapper, view) |
| | | |
| | | def test_add_view_same_phash_overrides_existing_single_view(self): |
| | | from pyramid.compat import md5 |
| | | from pyramid.renderers import null_renderer |
| | | from hashlib import md5 |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view, (IViewClassifier, IRequest, Interface), IView, name='') |
| | | def newview(context, request): |
| | | return 'OK' |
| | | config.add_view(view=newview, xhr=True) |
| | | config.add_view(view=newview, xhr=True, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_exc_same_phash_overrides_existing_single_view(self): |
| | | from pyramid.compat import md5 |
| | | from pyramid.renderers import null_renderer |
| | | from hashlib import md5 |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | IView, name='') |
| | | def newview(context, request): |
| | | return 'OK' |
| | | config.add_view(view=newview, xhr=True, context=RuntimeError) |
| | | config.add_view(view=newview, xhr=True, context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_default_phash_overrides_no_phash(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view, (IViewClassifier, IRequest, Interface), IView, name='') |
| | | def newview(context, request): |
| | | return 'OK' |
| | | config.add_view(view=newview) |
| | | config.add_view(view=newview, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_exc_default_phash_overrides_no_phash(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | IView, name='') |
| | | def newview(context, request): |
| | | return 'OK' |
| | | config.add_view(view=newview, context=RuntimeError) |
| | | config.add_view(view=newview, context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_default_phash_overrides_default_phash(self): |
| | | from pyramid.renderers import null_renderer |
| | | from pyramid.config import DEFAULT_PHASH |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | |
| | | view, (IViewClassifier, IRequest, Interface), IView, name='') |
| | | def newview(context, request): |
| | | return 'OK' |
| | | config.add_view(view=newview) |
| | | config.add_view(view=newview, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_exc_default_phash_overrides_default_phash(self): |
| | | from pyramid.renderers import null_renderer |
| | | from pyramid.config import DEFAULT_PHASH |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | |
| | | IView, name='') |
| | | def newview(context, request): |
| | | return 'OK' |
| | | config.add_view(view=newview, context=RuntimeError) |
| | | config.add_view(view=newview, context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_multiview_replaces_existing_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | config = self._makeOne(autocommit=True) |
| | | config.registry.registerAdapter( |
| | | view, (IViewClassifier, IRequest, Interface), IView, name='') |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | | |
| | | def test_add_view_exc_multiview_replaces_existing_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view, |
| | | (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), |
| | | IView, name='') |
| | | config.add_view(view=view, context=RuntimeError) |
| | | config.add_view(view=view, context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | | |
| | | def test_add_view_multiview_replaces_existing_securedview(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import ISecuredView |
| | |
| | | config.registry.registerAdapter( |
| | | view, (IViewClassifier, IRequest, Interface), |
| | | ISecuredView, name='') |
| | | config.add_view(view=view) |
| | | config.add_view(view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | | |
| | | def test_add_view_exc_multiview_replaces_existing_securedview(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import ISecuredView |
| | |
| | | view, |
| | | (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), |
| | | ISecuredView, name='') |
| | | config.add_view(view=view, context=RuntimeError) |
| | | config.add_view(view=view, context=RuntimeError, renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | | |
| | | def test_add_view_with_accept_multiview_replaces_existing_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | config = self._makeOne(autocommit=True) |
| | | config.registry.registerAdapter( |
| | | view, (IViewClassifier, IRequest, Interface), IView, name='') |
| | | config.add_view(view=view2, accept='text/html') |
| | | config.add_view(view=view2, accept='text/html', renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(len(wrapper.views), 1) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK2') |
| | | |
| | | def test_add_view_exc_with_accept_multiview_replaces_existing_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view, |
| | | (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), |
| | | IView, name='') |
| | | config.add_view(view=view2, accept='text/html', context=RuntimeError) |
| | | config.add_view(view=view2, accept='text/html', context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK2') |
| | | |
| | | def test_add_view_multiview_replaces_existing_view_with___accept__(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | config = self._makeOne(autocommit=True) |
| | | config.registry.registerAdapter( |
| | | view, (IViewClassifier, IRequest, Interface), IView, name='') |
| | | config.add_view(view=view2) |
| | | config.add_view(view=view2, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(len(wrapper.views), 1) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view, |
| | | (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), |
| | | IView, name='') |
| | | config.add_view(view=view2, context=RuntimeError) |
| | | config.add_view(view=view2, context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_multiview_replaces_multiview(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IMultiView |
| | |
| | | view, (IViewClassifier, IRequest, Interface), |
| | | IMultiView, name='') |
| | | view2 = lambda *arg: 'OK2' |
| | | config.add_view(view=view2) |
| | | config.add_view(view=view2, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)]) |
| | | self.assertEqual(wrapper(None, None), 'OK1') |
| | | |
| | | def test_add_view_exc_multiview_replaces_multiview(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IMultiView |
| | |
| | | (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)), |
| | | IMultiView, name='') |
| | | view2 = lambda *arg: 'OK2' |
| | | config.add_view(view=view2, context=RuntimeError) |
| | | config.add_view(view=view2, context=RuntimeError, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), exception_view=True) |
| | | self.assertTrue(IMultiView.providedBy(wrapper)) |
| | |
| | | self.assertEqual(wrapper(None, None), 'OK1') |
| | | |
| | | def test_add_view_multiview_context_superclass_then_subclass(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | config = self._makeOne(autocommit=True) |
| | | config.registry.registerAdapter( |
| | | view, (IViewClassifier, IRequest, ISuper), IView, name='') |
| | | config.add_view(view=view2, for_=ISub) |
| | | config.add_view(view=view2, for_=ISub, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, ISuper, IRequest) |
| | | self.assertFalse(IMultiView.providedBy(wrapper)) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | |
| | | self.assertEqual(wrapper(None, None), 'OK2') |
| | | |
| | | def test_add_view_multiview_exception_superclass_then_subclass(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IView |
| | |
| | | view, (IViewClassifier, IRequest, Super), IView, name='') |
| | | config.registry.registerAdapter( |
| | | view, (IExceptionViewClassifier, IRequest, Super), IView, name='') |
| | | config.add_view(view=view2, for_=Sub) |
| | | config.add_view(view=view2, for_=Sub, renderer=null_renderer) |
| | | wrapper = self._getViewCallable( |
| | | config, implementedBy(Super), IRequest) |
| | | wrapper_exc_view = self._getViewCallable( |
| | |
| | | self.assertEqual(wrapper_exc_view(None, None), 'OK2') |
| | | |
| | | def test_add_view_multiview_call_ordering(self): |
| | | from pyramid.renderers import null_renderer as nr |
| | | from zope.interface import directlyProvides |
| | | def view1(context, request): return 'view1' |
| | | def view2(context, request): return 'view2' |
| | |
| | | def view7(context, request): return 'view7' |
| | | def view8(context, request): return 'view8' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view1) |
| | | config.add_view(view=view2, request_method='POST') |
| | | config.add_view(view=view3,request_param='param') |
| | | config.add_view(view=view4, containment=IDummy) |
| | | config.add_view(view=view5, request_method='POST',request_param='param') |
| | | config.add_view(view=view6, request_method='POST', containment=IDummy) |
| | | config.add_view(view=view7, request_param='param', containment=IDummy) |
| | | config.add_view(view=view1, renderer=nr) |
| | | config.add_view(view=view2, request_method='POST', renderer=nr) |
| | | config.add_view(view=view3,request_param='param', renderer=nr) |
| | | config.add_view(view=view4, containment=IDummy, renderer=nr) |
| | | config.add_view(view=view5, request_method='POST', |
| | | request_param='param', renderer=nr) |
| | | config.add_view(view=view6, request_method='POST', containment=IDummy, |
| | | renderer=nr) |
| | | config.add_view(view=view7, request_param='param', containment=IDummy, |
| | | renderer=nr) |
| | | config.add_view(view=view8, request_method='POST',request_param='param', |
| | | containment=IDummy) |
| | | containment=IDummy, renderer=nr) |
| | | |
| | | |
| | | wrapper = self._getViewCallable(config) |
| | |
| | | self.assertEqual(result.settings, settings) |
| | | |
| | | def test_add_view_with_request_type_as_iface(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import directlyProvides |
| | | def view(context, request): |
| | | return 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(request_type=IDummy, view=view) |
| | | config.add_view(request_type=IDummy, view=view, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config, None) |
| | | request = self._makeRequest(config) |
| | | directlyProvides(request, IDummy) |
| | |
| | | config.add_view, view, '', None, None, object) |
| | | |
| | | def test_add_view_with_route_name(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.component import ComponentLookupError |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, route_name='foo') |
| | | config.add_view(view=view, route_name='foo', renderer=null_renderer) |
| | | self.assertEqual(len(config.registry.deferred_route_views), 1) |
| | | infos = config.registry.deferred_route_views['foo'] |
| | | self.assertEqual(len(infos), 1) |
| | |
| | | self.assertEqual(info['custom_predicates'], ('123',)) |
| | | |
| | | def test_add_view_with_route_name_exception(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from zope.component import ComponentLookupError |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, route_name='foo', context=RuntimeError) |
| | | config.add_view(view=view, route_name='foo', context=RuntimeError, |
| | | renderer=null_renderer) |
| | | self.assertEqual(len(config.registry.deferred_route_views), 1) |
| | | infos = config.registry.deferred_route_views['foo'] |
| | | self.assertEqual(len(infos), 1) |
| | |
| | | self.assertEqual(wrapper_exc_view(None, None), 'OK') |
| | | |
| | | def test_add_view_with_request_method_true(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, request_method='POST') |
| | | config.add_view(view=view, request_method='POST', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.method = 'POST' |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_request_param_noval_true(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, request_param='abc') |
| | | config.add_view(view=view, request_param='abc', renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.params = {'abc':''} |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_request_param_val_true(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, request_param='abc=123') |
| | | config.add_view(view=view, request_param='abc=123', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.params = {'abc':'123'} |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_xhr_true(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, xhr=True) |
| | | config.add_view(view=view, xhr=True, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.is_xhr = True |
| | |
| | | config.add_view, view=view, header='Host:a\\') |
| | | |
| | | def test_add_view_with_header_noval_match(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, header='Host') |
| | | config.add_view(view=view, header='Host', renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.headers = {'Host':'whatever'} |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_header_val_match(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, header=r'Host:\d') |
| | | config.add_view(view=view, header=r'Host:\d', renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.headers = {'Host':'1'} |
| | |
| | | self.assertRaises(HTTPNotFound, wrapper, None, request) |
| | | |
| | | def test_add_view_with_accept_match(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, accept='text/xml') |
| | | config.add_view(view=view, accept='text/xml', renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.accept = ['text/xml'] |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_containment_true(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import directlyProvides |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, containment=IDummy) |
| | | config.add_view(view=view, containment=IDummy, renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | context = DummyContext() |
| | | directlyProvides(context, IDummy) |
| | |
| | | self._assertNotFound(wrapper, context, None) |
| | | |
| | | def test_add_view_with_containment_dottedname(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import directlyProvides |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view( |
| | | view=view, |
| | | containment='pyramid.tests.test_config.IDummy') |
| | | containment='pyramid.tests.test_config.IDummy', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | context = DummyContext() |
| | | directlyProvides(context, IDummy) |
| | |
| | | config.add_view, view=view, path_info='\\') |
| | | |
| | | def test_add_view_with_path_info_match(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, path_info='/foo') |
| | | config.add_view(view=view, path_info='/foo', renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.path_info = '/foo' |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_custom_predicates_match(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | def pred1(context, request): |
| | |
| | | def pred2(context, request): |
| | | return True |
| | | predicates = (pred1, pred2) |
| | | config.add_view(view=view, custom_predicates=predicates) |
| | | config.add_view(view=view, custom_predicates=predicates, |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_custom_predicate_bests_standard_predicate(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | view2 = lambda *arg: 'NOT OK' |
| | | config = self._makeOne(autocommit=True) |
| | | def pred1(context, request): |
| | | return True |
| | | config.add_view(view=view, custom_predicates=(pred1,)) |
| | | config.add_view(view=view2, request_method='GET') |
| | | config.add_view(view=view, custom_predicates=(pred1,), |
| | | renderer=null_renderer) |
| | | config.add_view(view=view2, request_method='GET', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.method = 'GET' |
| | | self.assertEqual(wrapper(None, request), 'OK') |
| | | |
| | | def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self): |
| | | from pyramid.renderers import null_renderer |
| | | view = lambda *arg: 'OK' |
| | | view2 = lambda *arg: 'NOT OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, request_method='GET', xhr=True) |
| | | config.add_view(view=view2, request_method='GET') |
| | | config.add_view(view=view, request_method='GET', xhr=True, |
| | | renderer=null_renderer) |
| | | config.add_view(view=view2, request_method='GET', |
| | | renderer=null_renderer) |
| | | wrapper = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | request.method = 'GET' |
| | |
| | | self.assertRaises(ConfigurationConflictError, config.commit) |
| | | |
| | | def test_add_view_with_permission(self): |
| | | from pyramid.renderers import null_renderer |
| | | view1 = lambda *arg: 'OK' |
| | | outerself = self |
| | | class DummyPolicy(object): |
| | |
| | | config = self._makeOne(authorization_policy=policy, |
| | | authentication_policy=policy, |
| | | autocommit=True) |
| | | config.add_view(view=view1, permission='view') |
| | | config.add_view(view=view1, permission='view', renderer=null_renderer) |
| | | view = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | self.assertEqual(view(None, request), 'OK') |
| | | |
| | | def test_add_view_with_default_permission_no_explicit_permission(self): |
| | | from pyramid.renderers import null_renderer |
| | | view1 = lambda *arg: 'OK' |
| | | outerself = self |
| | | class DummyPolicy(object): |
| | |
| | | authentication_policy=policy, |
| | | default_permission='view', |
| | | autocommit=True) |
| | | config.add_view(view=view1) |
| | | config.add_view(view=view1, renderer=null_renderer) |
| | | view = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | self.assertEqual(view(None, request), 'OK') |
| | | |
| | | def test_add_view_with_no_default_permission_no_explicit_permission(self): |
| | | from pyramid.renderers import null_renderer |
| | | view1 = lambda *arg: 'OK' |
| | | class DummyPolicy(object): pass # wont be called |
| | | policy = DummyPolicy() |
| | | config = self._makeOne(authorization_policy=policy, |
| | | authentication_policy=policy, |
| | | autocommit=True) |
| | | config.add_view(view=view1) |
| | | config.add_view(view=view1, renderer=null_renderer) |
| | | view = self._getViewCallable(config) |
| | | request = self._makeRequest(config) |
| | | self.assertEqual(view(None, request), 'OK') |
| | |
| | | self.assertEqual(route.pattern, 'root/path') |
| | | |
| | | self._assertRoute(config, 'name', 'root/path') |
| | | |
| | | def test_add_route_discriminator(self): |
| | | config = self._makeOne() |
| | | route = config.add_route('name', 'path') |
| | | self._assertRoute(config, 'name', 'path') |
| | | self.assertEqual(route.name, 'name') |
| | | self.assertEqual(config._ctx.actions[-1][0], ('route', 'name')) |
| | | |
| | | def test_add_route_with_factory(self): |
| | | config = self._makeOne(autocommit=True) |
| | |
| | | raise AssertionError |
| | | |
| | | def test_derive_view_function(self): |
| | | from pyramid.renderers import null_renderer |
| | | def view(request): |
| | | return 'OK' |
| | | config = self._makeOne() |
| | | result = config.derive_view(view) |
| | | result = config.derive_view(view, renderer=null_renderer) |
| | | self.assertFalse(result is view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | |
| | | def test_derive_view_dottedname(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne() |
| | | result = config.derive_view( |
| | | 'pyramid.tests.test_config.dummy_view') |
| | | 'pyramid.tests.test_config.dummy_view', renderer=null_renderer) |
| | | self.assertFalse(result is dummy_view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | |
| | |
| | | self.assertEqual(config._ctx.info, 'abc') |
| | | |
| | | def test_add_static_here_no_utility_registered(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import Interface |
| | | from pyramid.static import PackageURLParser |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import IViewClassifier |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_static_view('static', 'fixtures/static') |
| | | config.add_static_view('static', 'fixtures/static', |
| | | renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'static/') |
| | | self._assertRoute(config, 'static/', 'static/*subpath') |
| | | wrapped = config.registry.adapters.lookup( |
| | | (IViewClassifier, request_type, Interface), IView, name='') |
| | | request = self._makeRequest(config) |
| | | self.assertEqual(wrapped(None, request).__class__, PackageURLParser) |
| | | result = wrapped(None, request) |
| | | self.assertEqual(result.__class__, PackageURLParser) |
| | | |
| | | def test_add_static_view_package_relative(self): |
| | | from pyramid.interfaces import IStaticURLInfo |
| | |
| | | [('static', static_path, {})]) |
| | | |
| | | def test_set_notfound_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: arg |
| | | config.set_notfound_view(view) |
| | | config.set_notfound_view(view, renderer=null_renderer) |
| | | request = self._makeRequest(config) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPNotFound), |
| | |
| | | self.assertEqual(result, (None, request)) |
| | | |
| | | def test_set_notfound_view_request_has_context(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: arg |
| | | config.set_notfound_view(view) |
| | | config.set_notfound_view(view, renderer=null_renderer) |
| | | request = self._makeRequest(config) |
| | | request.context = 'abc' |
| | | view = self._getViewCallable(config, |
| | |
| | | self.assertTrue('div' in result.body) |
| | | |
| | | def test_set_forbidden_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.set_forbidden_view(view) |
| | | config.set_forbidden_view(view, renderer=null_renderer) |
| | | request = self._makeRequest(config) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPForbidden), |
| | |
| | | self.assertEqual(result, 'OK') |
| | | |
| | | def test_set_forbidden_view_request_has_context(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: arg |
| | | config.set_forbidden_view(view) |
| | | config.set_forbidden_view(view, renderer=null_renderer) |
| | | request = self._makeRequest(config) |
| | | request.context = 'abc' |
| | | view = self._getViewCallable(config, |
| | |
| | | result = render_view_to_response(ctx, req, '') |
| | | self.assertEqual(result, 'grokked') |
| | | |
| | | def test_scan_integration_with_extra_kw(self): |
| | | config = self._makeOne(autocommit=True) |
| | | config.scan('pyramid.tests.venusianapp', a=1) |
| | | self.assertEqual(config.a, 1) |
| | | |
| | | def test_testing_securitypolicy(self): |
| | | from pyramid.testing import DummySecurityPolicy |
| | | config = self._makeOne(autocommit=True) |
| | |
| | | self.assertEqual(registeredview.__name__, 'view3') |
| | | |
| | | def test_autocommit_no_conflicts(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | def view1(request): pass |
| | | def view2(request): pass |
| | | def view3(request): pass |
| | | config.add_view(view1) |
| | | config.add_view(view2) |
| | | config.add_view(view3) |
| | | config.add_view(view1, renderer=null_renderer) |
| | | config.add_view(view2, renderer=null_renderer) |
| | | config.add_view(view3, renderer=null_renderer) |
| | | config.commit() |
| | | registeredview = self._getViewCallable(config) |
| | | self.assertEqual(registeredview.__name__, 'view3') |
| | |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.config import Configurator |
| | | return Configurator(*arg, **kw) |
| | | |
| | | config = Configurator(*arg, **kw) |
| | | config.registry._dont_resolve_responses = True |
| | | return config |
| | | |
| | | def _getRouteRequestIface(self, config, name): |
| | | from pyramid.interfaces import IRouteRequest |
| | | iface = config.registry.getUtility(IRouteRequest, name) |
| | |
| | | yield confinst[2] |
| | | |
| | | def test_add_route_with_view(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.add_route('name', 'path', view=view) |
| | | config.add_route('name', 'path', view=view, view_renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'name') |
| | | wrapper = self._getViewCallable(config, None, request_type) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | | self._assertRoute(config, 'name', 'path') |
| | | |
| | | def test_add_route_with_view_context(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.add_route('name', 'path', view=view, view_context=IDummy) |
| | | config.add_route('name', 'path', view=view, view_context=IDummy, |
| | | view_renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'name') |
| | | wrapper = self._getViewCallable(config, IDummy, request_type) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | |
| | | self.assertEqual(wrapper, None) |
| | | |
| | | def test_add_route_with_view_exception(self): |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.add_route('name', 'path', view=view, view_context=RuntimeError) |
| | | config.add_route('name', 'path', view=view, view_context=RuntimeError, |
| | | view_renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'name') |
| | | wrapper = self._getViewCallable( |
| | | config, ctx_iface=implementedBy(RuntimeError), |
| | |
| | | self.assertEqual(wrapper, None) |
| | | |
| | | def test_add_route_with_view_for(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.add_route('name', 'path', view=view, view_for=IDummy) |
| | | config.add_route('name', 'path', view=view, view_for=IDummy, |
| | | view_renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'name') |
| | | wrapper = self._getViewCallable(config, IDummy, request_type) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | |
| | | self.assertEqual(wrapper, None) |
| | | |
| | | def test_add_route_with_for_(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.add_route('name', 'path', view=view, for_=IDummy) |
| | | config.add_route('name', 'path', view=view, for_=IDummy, |
| | | view_renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'name') |
| | | wrapper = self._getViewCallable(config, IDummy, request_type) |
| | | self.assertEqual(wrapper(None, None), 'OK') |
| | |
| | | self.assertEqual(wrapper(None, None).body, 'Hello!') |
| | | |
| | | def test_add_route_with_view_attr(self): |
| | | from pyramid.renderers import null_renderer |
| | | config = self._makeOne(autocommit=True) |
| | | self._registerRenderer(config) |
| | | class View(object): |
| | |
| | | pass |
| | | def alt(self): |
| | | return 'OK' |
| | | config.add_route('name', 'path', view=View, view_attr='alt') |
| | | config.add_route('name', 'path', view=View, view_attr='alt', |
| | | view_renderer=null_renderer) |
| | | request_type = self._getRouteRequestIface(config, 'name') |
| | | wrapper = self._getViewCallable(config, None, request_type) |
| | | self._assertRoute(config, 'name', 'path') |
| | |
| | | self.config.registry.registerUtility(policy, IAuthorizationPolicy) |
| | | |
| | | def test_requestonly_function(self): |
| | | response = DummyResponse() |
| | | def view(request): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_requestonly_function_with_renderer(self): |
| | | response = DummyResponse() |
| | | class moo(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, 'OK') |
| | | self.assertEqual(view_inst, view) |
| | | self.assertEqual(ctx, context) |
| | | return 'moo' |
| | | return response |
| | | def view(request): |
| | | return 'OK' |
| | | deriver = self._makeOne(renderer=moo()) |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | | self.assertFalse(result.__wraps__ is view) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), 'moo') |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_requestonly_function_with_renderer_request_override(self): |
| | | def moo(info): |
| | |
| | | self.assertEqual(result(context, request).body, 'moo') |
| | | |
| | | def test_requestonly_function_with_renderer_request_has_view(self): |
| | | response = DummyResponse() |
| | | class moo(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, 'OK') |
| | | self.assertEqual(view_inst, 'view') |
| | | self.assertEqual(ctx, context) |
| | | return 'moo' |
| | | return response |
| | | def view(request): |
| | | return 'OK' |
| | | deriver = self._makeOne(renderer=moo()) |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | | self.assertFalse(result.__wraps__ is view) |
| | | request = self._makeRequest() |
| | | request.__view__ = 'view' |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), 'moo') |
| | | r = result(context, request) |
| | | self.assertEqual(r, response) |
| | | self.assertFalse(hasattr(request, '__view__')) |
| | | |
| | | def test_class_without_attr(self): |
| | | response = DummyResponse() |
| | | class View(object): |
| | | def __init__(self, request): |
| | | pass |
| | | def __call__(self): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(View) |
| | | request = self._makeRequest() |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(request.__view__.__class__, View) |
| | | |
| | | def test_class_with_attr(self): |
| | | response = DummyResponse() |
| | | class View(object): |
| | | def __init__(self, request): |
| | | pass |
| | | def another(self): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne(attr='another') |
| | | result = deriver(View) |
| | | request = self._makeRequest() |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(request.__view__.__class__, View) |
| | | |
| | | def test_as_function_context_and_request(self): |
| | |
| | | return 'OK' |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertTrue(result is view) |
| | | self.assertTrue(result.__wraps__ is view) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | self.assertEqual(view(None, None), 'OK') |
| | | |
| | | def test_as_function_requestonly(self): |
| | | response = DummyResponse() |
| | | def view(request): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | |
| | | self.assertEqual(view.__doc__, result.__doc__) |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_as_newstyle_class_context_and_request(self): |
| | | response = DummyResponse() |
| | | class view(object): |
| | | def __init__(self, context, request): |
| | | pass |
| | | def __call__(self): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | request = self._makeRequest() |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(request.__view__.__class__, view) |
| | | |
| | | def test_as_newstyle_class_requestonly(self): |
| | | response = DummyResponse() |
| | | class view(object): |
| | | def __init__(self, context, request): |
| | | pass |
| | | def __call__(self): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | request = self._makeRequest() |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(request.__view__.__class__, view) |
| | | |
| | | def test_as_oldstyle_class_context_and_request(self): |
| | | response = DummyResponse() |
| | | class view: |
| | | def __init__(self, context, request): |
| | | pass |
| | | def __call__(self): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | request = self._makeRequest() |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(request.__view__.__class__, view) |
| | | |
| | | def test_as_oldstyle_class_requestonly(self): |
| | | response = DummyResponse() |
| | | class view: |
| | | def __init__(self, context, request): |
| | | pass |
| | | def __call__(self): |
| | | return 'OK' |
| | | return response |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | request = self._makeRequest() |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(request.__view__.__class__, view) |
| | | |
| | | def test_as_instance_context_and_request(self): |
| | | response = DummyResponse() |
| | | class View: |
| | | def __call__(self, context, request): |
| | | return 'OK' |
| | | return response |
| | | view = View() |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertTrue(result is view) |
| | | self.assertTrue(result.__wraps__ is view) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_as_instance_requestonly(self): |
| | | response = DummyResponse() |
| | | class View: |
| | | def __call__(self, request): |
| | | return 'OK' |
| | | return response |
| | | view = View() |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | |
| | | self.assertEqual(view.__doc__, result.__doc__) |
| | | self.assertTrue('instance' in result.__name__) |
| | | self.assertFalse(hasattr(result, '__call_permissive__')) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_with_debug_authorization_no_authpol(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | | logger = self._registerLogger() |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | |
| | | "(no authorization policy in use)") |
| | | |
| | | def test_with_debug_authorization_authn_policy_no_authz_policy(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict(debug_authorization=True) |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | policy = DummySecurityPolicy(False) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | |
| | | "(no authorization policy in use)") |
| | | |
| | | def test_with_debug_authorization_authz_policy_no_authn_policy(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict(debug_authorization=True) |
| | | from pyramid.interfaces import IAuthorizationPolicy |
| | | policy = DummySecurityPolicy(False) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | |
| | | "(no authorization policy in use)") |
| | | |
| | | def test_with_debug_authorization_no_permission(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | | self._registerSecurityPolicy(True) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | |
| | | "no permission registered)") |
| | | |
| | | def test_debug_auth_permission_authpol_permitted(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | | logger = self._registerLogger() |
| | |
| | | self.assertEqual(view.__module__, result.__module__) |
| | | self.assertEqual(view.__doc__, result.__doc__) |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertEqual(result.__call_permissive__, view) |
| | | self.assertEqual(result.__call_permissive__.__wraps__, view) |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | | "'view_name' against context None): True") |
| | | |
| | | def test_debug_auth_permission_authpol_permitted_no_request(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | | logger = self._registerLogger() |
| | |
| | | self.assertEqual(view.__module__, result.__module__) |
| | | self.assertEqual(view.__doc__, result.__doc__) |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertEqual(result.__call_permissive__, view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertEqual(result.__call_permissive__.__wraps__, view) |
| | | self.assertEqual(result(None, None), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url None (view name " |
| | |
| | | |
| | | def test_debug_auth_permission_authpol_denied(self): |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | | logger = self._registerLogger() |
| | |
| | | self.assertEqual(view.__module__, result.__module__) |
| | | self.assertEqual(view.__doc__, result.__doc__) |
| | | self.assertEqual(view.__name__, result.__name__) |
| | | self.assertEqual(result.__call_permissive__, view) |
| | | self.assertEqual(result.__call_permissive__.__wraps__, view) |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | |
| | | self.assertEqual(permitted, False) |
| | | |
| | | def test_debug_auth_permission_authpol_overridden(self): |
| | | view = lambda *arg: 'OK' |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | | logger = self._registerLogger() |
| | | self._registerSecurityPolicy(False) |
| | | deriver = self._makeOne(permission='__no_permission_required__') |
| | | deriver = self._makeOne(permission=NO_PERMISSION_REQUIRED) |
| | | result = deriver(view) |
| | | self.assertEqual(view.__module__, result.__module__) |
| | | self.assertEqual(view.__doc__, result.__doc__) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | | "'view_name' against context None): False") |
| | | |
| | | def test_secured_view_authn_policy_no_authz_policy(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = {} |
| | | from pyramid.interfaces import IAuthenticationPolicy |
| | | policy = DummySecurityPolicy(False) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | |
| | | def test_secured_view_authz_policy_no_authn_policy(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | self.config.registry.settings = {} |
| | | from pyramid.interfaces import IAuthorizationPolicy |
| | | policy = DummySecurityPolicy(False) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertEqual(result(None, request), 'OK') |
| | | self.assertEqual(result(None, request), response) |
| | | |
| | | def test_with_predicates_all(self): |
| | | view = lambda *arg: 'OK' |
| | | response = DummyResponse() |
| | | view = lambda *arg: response |
| | | predicates = [] |
| | | def predicate1(context, request): |
| | | predicates.append(True) |
| | |
| | | request = self._makeRequest() |
| | | request.method = 'POST' |
| | | next = result(None, None) |
| | | self.assertEqual(next, 'OK') |
| | | self.assertEqual(next, response) |
| | | self.assertEqual(predicates, [True, True]) |
| | | |
| | | def test_with_predicates_checker(self): |
| | |
| | | self.assertEqual(predicates, [True, True]) |
| | | |
| | | def test_with_wrapper_viewname(self): |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import IViewClassifier |
| | | inner_response = Response('OK') |
| | |
| | | def outer_view(context, request): |
| | | self.assertEqual(request.wrapped_response, inner_response) |
| | | self.assertEqual(request.wrapped_body, inner_response.body) |
| | | self.assertEqual(request.wrapped_view, inner_view) |
| | | self.assertEqual(request.wrapped_view.__original_view__, |
| | | inner_view) |
| | | return Response('outer ' + request.wrapped_body) |
| | | self.config.registry.registerAdapter( |
| | | outer_view, (IViewClassifier, None, None), IView, 'owrap') |
| | |
| | | self.assertEqual(response.body, 'outer OK') |
| | | |
| | | def test_with_wrapper_viewname_notfound(self): |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | inner_response = Response('OK') |
| | | def inner_view(context, request): |
| | | return inner_response |
| | |
| | | self.assertRaises(ValueError, wrapped, None, request) |
| | | |
| | | def test_as_newstyle_class_context_and_request_attr_and_renderer(self): |
| | | response = DummyResponse() |
| | | class renderer(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, {'a':'1'}) |
| | | self.assertEqual(view_inst.__class__, View) |
| | | self.assertEqual(ctx, context) |
| | | return resp |
| | | return response |
| | | class View(object): |
| | | def __init__(self, context, request): |
| | | pass |
| | |
| | | self.assertEqual(result.__name__, View.__name__) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), {'a':'1'}) |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_as_newstyle_class_requestonly_attr_and_renderer(self): |
| | | response = DummyResponse() |
| | | class renderer(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, {'a':'1'}) |
| | | self.assertEqual(view_inst.__class__, View) |
| | | self.assertEqual(ctx, context) |
| | | return resp |
| | | return response |
| | | class View(object): |
| | | def __init__(self, request): |
| | | pass |
| | |
| | | self.assertEqual(result.__name__, View.__name__) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), {'a':'1'}) |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_as_oldstyle_cls_context_request_attr_and_renderer(self): |
| | | response = DummyResponse() |
| | | class renderer(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, {'a':'1'}) |
| | | self.assertEqual(view_inst.__class__, View) |
| | | self.assertEqual(ctx, context) |
| | | return resp |
| | | return response |
| | | class View: |
| | | def __init__(self, context, request): |
| | | pass |
| | |
| | | self.assertEqual(result.__name__, View.__name__) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), {'a':'1'}) |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_as_oldstyle_cls_requestonly_attr_and_renderer(self): |
| | | response = DummyResponse() |
| | | class renderer(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, {'a':'1'}) |
| | | self.assertEqual(view_inst.__class__, View) |
| | | self.assertEqual(ctx, context) |
| | | return resp |
| | | return response |
| | | class View: |
| | | def __init__(self, request): |
| | | pass |
| | |
| | | self.assertEqual(result.__name__, View.__name__) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), {'a':'1'}) |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_as_instance_context_and_request_attr_and_renderer(self): |
| | | response = DummyResponse() |
| | | class renderer(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, {'a':'1'}) |
| | | self.assertEqual(view_inst, view) |
| | | self.assertEqual(ctx, context) |
| | | return resp |
| | | return response |
| | | class View: |
| | | def index(self, context, request): |
| | | return {'a':'1'} |
| | |
| | | self.assertEqual(result.__doc__, view.__doc__) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), {'a':'1'}) |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_as_instance_requestonly_attr_and_renderer(self): |
| | | response = DummyResponse() |
| | | class renderer(object): |
| | | def render_view(inself, req, resp, view_inst, ctx): |
| | | self.assertEqual(req, request) |
| | | self.assertEqual(resp, {'a':'1'}) |
| | | self.assertEqual(view_inst, view) |
| | | self.assertEqual(ctx, context) |
| | | return resp |
| | | return response |
| | | class View: |
| | | def index(self, request): |
| | | return {'a':'1'} |
| | |
| | | self.assertEqual(result.__doc__, view.__doc__) |
| | | request = self._makeRequest() |
| | | context = testing.DummyResource() |
| | | self.assertEqual(result(context, request), {'a':'1'}) |
| | | self.assertEqual(result(context, request), response) |
| | | |
| | | def test_with_view_mapper_config_specified(self): |
| | | response = DummyResponse() |
| | | class mapper(object): |
| | | def __init__(self, **kw): |
| | | self.kw = kw |
| | | def __call__(self, view): |
| | | def wrapped(context, request): |
| | | return 'OK' |
| | | return response |
| | | return wrapped |
| | | def view(context, request): return 'NOTOK' |
| | | deriver = self._makeOne(mapper=mapper) |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertFalse(result.__wraps__ is view) |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_with_view_mapper_view_specified(self): |
| | | from pyramid.response import Response |
| | | response = Response() |
| | | def mapper(**kw): |
| | | def inner(view): |
| | | def superinner(context, request): |
| | | self.assertEqual(request, None) |
| | | return 'OK' |
| | | return response |
| | | return superinner |
| | | return inner |
| | | def view(context, request): return 'NOTOK' |
| | | view.__view_mapper__ = mapper |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertFalse(result.__wraps__ is view) |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_with_view_mapper_default_mapper_specified(self): |
| | | from pyramid.response import Response |
| | | response = Response() |
| | | def mapper(**kw): |
| | | def inner(view): |
| | | def superinner(context, request): |
| | | self.assertEqual(request, None) |
| | | return 'OK' |
| | | return response |
| | | return superinner |
| | | return inner |
| | | self.config.set_view_mapper(mapper) |
| | | def view(context, request): return 'NOTOK' |
| | | deriver = self._makeOne() |
| | | result = deriver(view) |
| | | self.assertFalse(result is view) |
| | | self.assertEqual(result(None, None), 'OK') |
| | | self.assertFalse(result.__wraps__ is view) |
| | | self.assertEqual(result(None, None), response) |
| | | |
| | | def test_attr_wrapped_view_branching_default_phash(self): |
| | | from pyramid.config import DEFAULT_PHASH |
| | | def view(context, request): pass |
| | | deriver = self._makeOne(phash=DEFAULT_PHASH) |
| | | result = deriver(view) |
| | | self.assertEqual(result, view) |
| | | self.assertEqual(result.__wraps__, view) |
| | | |
| | | def test_attr_wrapped_view_branching_nondefault_phash(self): |
| | | def view(context, request): pass |
| | |
| | | |
| | | def test_http_cached_view_integer(self): |
| | | import datetime |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | response = Response('OK') |
| | | def inner_view(context, request): |
| | | return response |
| | |
| | | |
| | | def test_http_cached_view_timedelta(self): |
| | | import datetime |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | response = Response('OK') |
| | | def inner_view(context, request): |
| | | return response |
| | |
| | | |
| | | def test_http_cached_view_tuple(self): |
| | | import datetime |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | response = Response('OK') |
| | | def inner_view(context, request): |
| | | return response |
| | |
| | | self.assertEqual(headers['Cache-Control'], 'max-age=3600, public') |
| | | |
| | | def test_http_cached_view_tuple_seconds_None(self): |
| | | from webob import Response |
| | | from pyramid.response import Response |
| | | response = Response('OK') |
| | | def inner_view(context, request): |
| | | return response |
| | |
| | | self.assertFalse('Expires' in headers) |
| | | self.assertEqual(headers['Cache-Control'], 'public') |
| | | |
| | | def test_http_cached_view_nonresponse_object_returned_downstream(self): |
| | | def test_http_cached_view_prevent_auto_set(self): |
| | | from pyramid.response import Response |
| | | response = Response() |
| | | response.cache_control.prevent_auto = True |
| | | def inner_view(context, request): |
| | | return None |
| | | return response |
| | | deriver = self._makeOne(http_cache=3600) |
| | | result = deriver(inner_view) |
| | | self.assertFalse(result is inner_view) |
| | | self.assertEqual(inner_view.__module__, result.__module__) |
| | | self.assertEqual(inner_view.__doc__, result.__doc__) |
| | | request = self._makeRequest() |
| | | result = result(None, request) |
| | | self.assertEqual(result, None) # doesn't blow up |
| | | self.assertEqual(result, response) # doesn't blow up |
| | | headers = dict(result.headerlist) |
| | | self.assertFalse('Expires' in headers) |
| | | self.assertFalse('Cache-Control' in headers) |
| | | |
| | | def test_http_cached_prevent_http_cache_in_settings(self): |
| | | self.config.registry.settings['prevent_http_cache'] = True |
| | | from pyramid.response import Response |
| | | response = Response() |
| | | def inner_view(context, request): |
| | | return response |
| | | deriver = self._makeOne(http_cache=3600) |
| | | result = deriver(inner_view) |
| | | request = self._makeRequest() |
| | | result = result(None, request) |
| | | self.assertEqual(result, response) |
| | | headers = dict(result.headerlist) |
| | | self.assertFalse('Expires' in headers) |
| | | self.assertFalse('Cache-Control' in headers) |
| | | |
| | | def test_http_cached_view_bad_tuple(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | |
| | | """ """ |
| | | |
| | | def dummy_include(config): |
| | | config.registry.included = True |
| | | config.action('discrim', None, config.package) |
| | | |
| | | def dummy_include2(config): |
| | | config.registry.also_included = True |
| | | config.action('discrim', None, config.package) |
| | | |
| | | includeme = dummy_include |
| | |
| | | |
| | | def parse_httpdate(s): |
| | | import datetime |
| | | return datetime.datetime.strptime(s, "%a, %d %b %Y %H:%M:%S %Z") |
| | | # cannot use %Z, must use literal GMT; Jython honors timezone |
| | | # but CPython does not |
| | | return datetime.datetime.strptime(s, "%a, %d %b %Y %H:%M:%S GMT") |
| | | |
| | | def assert_similar_datetime(one, two): |
| | | for attr in ('year', 'month', 'day', 'hour', 'minute'): |
| | | assert(getattr(one, attr) == getattr(two, attr)) |
| | | one_attr = getattr(one, attr) |
| | | two_attr = getattr(two, attr) |
| | | if not one_attr == two_attr: # pragma: no cover |
| | | raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr)) |
| | | |
| | | from pyramid.interfaces import IResponse |
| | | class DummyResponse(object): |
| | | implements(IResponse) |
| | | |
| | | def dummy_tween_factory(handler, registry): pass |
| | |
| | | [(foo, dec.register, 'pyramid')]) |
| | | |
| | | class TestBeforeRender(unittest.TestCase): |
| | | def _makeOne(self, system): |
| | | def _makeOne(self, system, val=None): |
| | | from pyramid.events import BeforeRender |
| | | return BeforeRender(system) |
| | | return BeforeRender(system, val) |
| | | |
| | | def test_instance_conforms(self): |
| | | from zope.interface.verify import verifyObject |
| | |
| | | event['a'] = 1 |
| | | self.assertEqual(system, {'a':1}) |
| | | |
| | | def test_setitem_fail(self): |
| | | system = {'a':1} |
| | | def test_setdefault_fail(self): |
| | | system = {} |
| | | event = self._makeOne(system) |
| | | self.assertRaises(KeyError, event.__setitem__, 'a', 1) |
| | | result = event.setdefault('a', 1) |
| | | self.assertEqual(result, 1) |
| | | self.assertEqual(system, {'a':1}) |
| | | |
| | | def test_setdefault_success(self): |
| | | system = {} |
| | | event = self._makeOne(system) |
| | | event['a'] = 1 |
| | | result = event.setdefault('a', 2) |
| | | self.assertEqual(result, 1) |
| | | self.assertEqual(system, {'a':1}) |
| | | |
| | | def test_update_success(self): |
| | | system = {'a':1} |
| | | event = self._makeOne(system) |
| | | event.update({'b':2}) |
| | | self.assertEqual(system, {'a':1, 'b':2}) |
| | | |
| | | def test_update_fail(self): |
| | | system = {'a':1} |
| | | event = self._makeOne(system) |
| | | self.assertRaises(KeyError, event.update, {'a':1}) |
| | | |
| | | def test__contains__True(self): |
| | | system = {'a':1} |
| | |
| | | event = self._makeOne(system) |
| | | self.assertEqual(event.get('a'), None) |
| | | |
| | | def test_rendering_val(self): |
| | | system = {} |
| | | val = {} |
| | | event = self._makeOne(system, val) |
| | | self.assertTrue(event.rendering_val is val) |
| | | |
| | | class DummyConfigurator(object): |
| | | def __init__(self): |
| | |
| | | body = list(exc(environ, start_response))[0] |
| | | self.assertEqual(body, '200 OK\n\nGET') |
| | | |
| | | def test_custom_body_template_with_custom_variable_doesnt_choke(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(body_template='${REQUEST_METHOD}') |
| | | environ = _makeEnviron() |
| | | class Choke(object): |
| | | def __str__(self): raise ValueError |
| | | environ['gardentheory.user'] = Choke() |
| | | start_response = DummyStartResponse() |
| | | body = list(exc(environ, start_response))[0] |
| | | self.assertEqual(body, '200 OK\n\nGET') |
| | | |
| | | def test_body_template_unicode(self): |
| | | cls = self._getTargetSubclass() |
| | | la = unicode('/La Pe\xc3\xb1a', 'utf-8') |
| | |
| | | ) |
| | | self.assertTrue(localizer.pluralizer is pluralizer) |
| | | |
| | | def test_pluralize_default_translations(self): |
| | | # test that even without message ids loaded that |
| | | # "localizer.pluralize" "works" instead of raising an inscrutable |
| | | # "translations object has no attr 'plural' error; see |
| | | # see https://github.com/Pylons/pyramid/issues/235 |
| | | from pyramid.i18n import Translations |
| | | translations = Translations() |
| | | translations._catalog = {} |
| | | localizer = self._makeOne(None, translations) |
| | | result = localizer.pluralize('singular', 'plural', 2, domain='1', |
| | | mapping={}) |
| | | self.assertEqual(result, 'plural') |
| | | |
| | | class Test_negotiate_locale_name(unittest.TestCase): |
| | | def setUp(self): |
| | | cleanUp() |
| | |
| | | self.assertEqual(t.dungettext('messages', 'foo1', 'foos1', 1), 'Voh1') |
| | | self.assertEqual(t.dungettext('messages1', 'foo1', 'foos1', 1), 'VohD1') |
| | | |
| | | def test_default_germanic_pluralization(self): |
| | | t = self._getTargetClass()() |
| | | t._catalog = {} |
| | | result = t.dungettext('messages', 'foo1', 'foos1', 2) |
| | | self.assertEqual(result, 'foos1') |
| | | |
| | | |
| | | class DummyRequest(object): |
| | | def __init__(self): |
| | |
| | | |
| | | from pyramid.wsgi import wsgiapp |
| | | from pyramid.view import view_config |
| | | from pyramid.view import static |
| | | from pyramid.static import static_view |
| | | |
| | | from zope.interface import Interface |
| | | |
| | |
| | | reg = config.registry |
| | | view = reg.adapters.lookup( |
| | | (IViewClassifier, IRequest, INothing), IView, name='') |
| | | self.assertEqual(view, wsgiapptest) |
| | | self.assertEqual(view.__original_view__, wsgiapptest) |
| | | |
| | | here = os.path.dirname(__file__) |
| | | staticapp = static(os.path.join(here, 'fixtures')) |
| | | staticapp = static_view(os.path.join(here, 'fixtures'), use_subpath=True) |
| | | |
| | | class TestStaticApp(unittest.TestCase): |
| | | def test_basic(self): |
| | |
| | | from pyramid.paster import PShellCommand |
| | | return PShellCommand |
| | | |
| | | def _makeOne(self): |
| | | return self._getTargetClass()('pshell') |
| | | def _makeOne(self, patch_bootstrap=True, patch_config=True, |
| | | patch_args=True, patch_options=True): |
| | | cmd = self._getTargetClass()('pshell') |
| | | if patch_bootstrap: |
| | | self.bootstrap = DummyBootstrap() |
| | | cmd.bootstrap = (self.bootstrap,) |
| | | if patch_config: |
| | | self.config_factory = DummyConfigParserFactory() |
| | | cmd.ConfigParser = self.config_factory |
| | | if patch_args: |
| | | self.args = ('/foo/bar/myapp.ini#myapp',) |
| | | cmd.args = self.args |
| | | if patch_options: |
| | | class Options(object): pass |
| | | self.options = Options() |
| | | self.options.disable_ipython = True |
| | | cmd.options = self.options |
| | | return cmd |
| | | |
| | | def test_command_ipshell_is_None_ipython_enabled(self): |
| | | def test_make_default_shell(self): |
| | | command = self._makeOne() |
| | | interact = DummyInteractor() |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.interact = (interact,) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | class Options(object): pass |
| | | command.options = Options() |
| | | command.options.disable_ipython = False |
| | | command.command(IPShell=None) |
| | | self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') |
| | | self.assertEqual(loadapp.section_name, 'myapp') |
| | | self.assertTrue(loadapp.relative_to) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | | pushed = app.threadlocal_manager.pushed[0] |
| | | self.assertEqual(pushed['registry'], dummy_registry) |
| | | self.assertEqual(pushed['request'].registry, dummy_registry) |
| | | self.assertEqual(interact.local, {'root':dummy_root, |
| | | 'registry':dummy_registry}) |
| | | self.assertTrue(interact.banner) |
| | | self.assertEqual(len(app.threadlocal_manager.popped), 1) |
| | | shell = command.make_default_shell(interact) |
| | | shell({'foo': 'bar'}, 'a help message') |
| | | self.assertEqual(interact.local, {'foo': 'bar'}) |
| | | self.assertTrue('a help message' in interact.banner) |
| | | |
| | | def test_command_ipshell_is_not_None_ipython_disabled(self): |
| | | def test_make_ipython_v0_11_shell(self): |
| | | command = self._makeOne() |
| | | interact = DummyInteractor() |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.interact = (interact,) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | class Options(object): pass |
| | | command.options = Options() |
| | | ipshell_factory = DummyIPShellFactory() |
| | | shell = command.make_ipython_v0_11_shell(ipshell_factory) |
| | | shell({'foo': 'bar'}, 'a help message') |
| | | self.assertEqual(ipshell_factory.kw['user_ns'], {'foo': 'bar'}) |
| | | self.assertTrue('a help message' in ipshell_factory.kw['banner2']) |
| | | self.assertTrue(ipshell_factory.shell.called) |
| | | |
| | | def test_make_ipython_v0_10_shell(self): |
| | | command = self._makeOne() |
| | | ipshell_factory = DummyIPShellFactory() |
| | | shell = command.make_ipython_v0_10_shell(ipshell_factory) |
| | | shell({'foo': 'bar'}, 'a help message') |
| | | self.assertEqual(ipshell_factory.kw['argv'], []) |
| | | self.assertEqual(ipshell_factory.kw['user_ns'], {'foo': 'bar'}) |
| | | self.assertTrue('a help message' in ipshell_factory.shell.banner) |
| | | self.assertTrue(ipshell_factory.shell.called) |
| | | |
| | | def test_command_loads_default_shell(self): |
| | | command = self._makeOne() |
| | | shell = DummyShell() |
| | | command.make_ipython_v0_11_shell = lambda: None |
| | | command.make_ipython_v0_10_shell = lambda: None |
| | | command.make_default_shell = lambda: shell |
| | | command.command() |
| | | self.assertTrue(self.config_factory.parser) |
| | | self.assertEqual(self.config_factory.parser.filename, |
| | | '/foo/bar/myapp.ini') |
| | | self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') |
| | | self.assertEqual(shell.env, { |
| | | 'app':self.bootstrap.app, 'root':self.bootstrap.root, |
| | | 'registry':self.bootstrap.registry, |
| | | 'request':self.bootstrap.request, |
| | | 'root_factory':self.bootstrap.root_factory, |
| | | }) |
| | | self.assertTrue(self.bootstrap.closer.called) |
| | | self.assertTrue(shell.help) |
| | | |
| | | def test_command_loads_default_shell_with_ipython_disabled(self): |
| | | command = self._makeOne() |
| | | shell = DummyShell() |
| | | bad_shell = DummyShell() |
| | | command.make_ipython_v0_11_shell = lambda: bad_shell |
| | | command.make_ipython_v0_10_shell = lambda: bad_shell |
| | | command.make_default_shell = lambda: shell |
| | | command.options.disable_ipython = True |
| | | command.command(IPShell='notnone') |
| | | self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') |
| | | self.assertEqual(loadapp.section_name, 'myapp') |
| | | self.assertTrue(loadapp.relative_to) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | | pushed = app.threadlocal_manager.pushed[0] |
| | | self.assertEqual(pushed['registry'], dummy_registry) |
| | | self.assertEqual(pushed['request'].registry, dummy_registry) |
| | | self.assertEqual(interact.local, {'root':dummy_root, |
| | | 'registry':dummy_registry}) |
| | | self.assertTrue(interact.banner) |
| | | self.assertEqual(len(app.threadlocal_manager.popped), 1) |
| | | command.command() |
| | | self.assertTrue(self.config_factory.parser) |
| | | self.assertEqual(self.config_factory.parser.filename, |
| | | '/foo/bar/myapp.ini') |
| | | self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') |
| | | self.assertEqual(shell.env, { |
| | | 'app':self.bootstrap.app, 'root':self.bootstrap.root, |
| | | 'registry':self.bootstrap.registry, |
| | | 'request':self.bootstrap.request, |
| | | 'root_factory':self.bootstrap.root_factory, |
| | | }) |
| | | self.assertEqual(bad_shell.env, {}) |
| | | self.assertTrue(self.bootstrap.closer.called) |
| | | self.assertTrue(shell.help) |
| | | |
| | | def test_command_ipython_enabled(self): |
| | | def test_command_loads_ipython_v0_11(self): |
| | | command = self._makeOne() |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | dummy_shell_factory = DummyIPShellFactory() |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | class Options(object): pass |
| | | command.options = Options() |
| | | shell = DummyShell() |
| | | command.make_ipython_v0_11_shell = lambda: shell |
| | | command.make_ipython_v0_10_shell = lambda: None |
| | | command.make_default_shell = lambda: None |
| | | command.options.disable_ipython = False |
| | | command.command(IPShell=dummy_shell_factory) |
| | | self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') |
| | | self.assertEqual(loadapp.section_name, 'myapp') |
| | | self.assertTrue(loadapp.relative_to) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | | pushed = app.threadlocal_manager.pushed[0] |
| | | self.assertEqual(pushed['registry'], dummy_registry) |
| | | self.assertEqual(pushed['request'].registry, dummy_registry) |
| | | self.assertEqual(dummy_shell_factory.shell.local_ns, |
| | | {'root':dummy_root, 'registry':dummy_registry}) |
| | | self.assertEqual(dummy_shell_factory.shell.global_ns, {}) |
| | | self.assertTrue('\n\n' in dummy_shell_factory.shell.IP.BANNER) |
| | | self.assertEqual(len(app.threadlocal_manager.popped), 1) |
| | | command.command() |
| | | self.assertTrue(self.config_factory.parser) |
| | | self.assertEqual(self.config_factory.parser.filename, |
| | | '/foo/bar/myapp.ini') |
| | | self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') |
| | | self.assertEqual(shell.env, { |
| | | 'app':self.bootstrap.app, 'root':self.bootstrap.root, |
| | | 'registry':self.bootstrap.registry, |
| | | 'request':self.bootstrap.request, |
| | | 'root_factory':self.bootstrap.root_factory, |
| | | }) |
| | | self.assertTrue(self.bootstrap.closer.called) |
| | | self.assertTrue(shell.help) |
| | | |
| | | def test_command_get_app_hookable(self): |
| | | from paste.deploy import loadapp |
| | | def test_command_loads_ipython_v0_10(self): |
| | | command = self._makeOne() |
| | | app = DummyApp() |
| | | apped = [] |
| | | def get_app(*arg, **kw): |
| | | apped.append((arg, kw)) |
| | | return app |
| | | command.get_app = get_app |
| | | interact = DummyInteractor() |
| | | app = DummyApp() |
| | | command.interact = (interact,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | class Options(object): pass |
| | | command.options = Options() |
| | | command.options.disable_ipython =True |
| | | command.command(IPShell=None) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | | pushed = app.threadlocal_manager.pushed[0] |
| | | self.assertEqual(pushed['registry'], dummy_registry) |
| | | self.assertEqual(pushed['request'].registry, dummy_registry) |
| | | self.assertEqual(interact.local, {'root':dummy_root, |
| | | 'registry':dummy_registry}) |
| | | self.assertTrue(interact.banner) |
| | | self.assertEqual(len(app.threadlocal_manager.popped), 1) |
| | | self.assertEqual(apped, [(('/foo/bar/myapp.ini', 'myapp'), |
| | | {'loadapp': loadapp})]) |
| | | shell = DummyShell() |
| | | command.make_ipython_v0_11_shell = lambda: None |
| | | command.make_ipython_v0_10_shell = lambda: shell |
| | | command.make_default_shell = lambda: None |
| | | command.options.disable_ipython = False |
| | | command.command() |
| | | self.assertTrue(self.config_factory.parser) |
| | | self.assertEqual(self.config_factory.parser.filename, |
| | | '/foo/bar/myapp.ini') |
| | | self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') |
| | | self.assertEqual(shell.env, { |
| | | 'app':self.bootstrap.app, 'root':self.bootstrap.root, |
| | | 'registry':self.bootstrap.registry, |
| | | 'request':self.bootstrap.request, |
| | | 'root_factory':self.bootstrap.root_factory, |
| | | }) |
| | | self.assertTrue(self.bootstrap.closer.called) |
| | | self.assertTrue(shell.help) |
| | | |
| | | def test_command_get_root_hookable(self): |
| | | def test_command_loads_custom_items(self): |
| | | command = self._makeOne() |
| | | interact = DummyInteractor() |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.interact = (interact,) |
| | | command.loadapp = (loadapp,) |
| | | root = Dummy() |
| | | apps = [] |
| | | def get_root(app): |
| | | apps.append(app) |
| | | return root, lambda *arg: None |
| | | command.get_root =get_root |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | class Options(object): pass |
| | | command.options = Options() |
| | | command.options.disable_ipython =True |
| | | command.command(IPShell=None) |
| | | self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') |
| | | self.assertEqual(loadapp.section_name, 'myapp') |
| | | self.assertTrue(loadapp.relative_to) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 0) |
| | | self.assertEqual(interact.local, {'root':root, |
| | | 'registry':dummy_registry}) |
| | | self.assertTrue(interact.banner) |
| | | self.assertEqual(apps, [app]) |
| | | model = Dummy() |
| | | self.config_factory.items = [('m', model)] |
| | | shell = DummyShell() |
| | | command.command(shell) |
| | | self.assertTrue(self.config_factory.parser) |
| | | self.assertEqual(self.config_factory.parser.filename, |
| | | '/foo/bar/myapp.ini') |
| | | self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') |
| | | self.assertEqual(shell.env, { |
| | | 'app':self.bootstrap.app, 'root':self.bootstrap.root, |
| | | 'registry':self.bootstrap.registry, |
| | | 'request':self.bootstrap.request, |
| | | 'root_factory':self.bootstrap.root_factory, |
| | | 'm':model, |
| | | }) |
| | | self.assertTrue(self.bootstrap.closer.called) |
| | | self.assertTrue(shell.help) |
| | | |
| | | def test_command_custom_section_override(self): |
| | | command = self._makeOne() |
| | | dummy = Dummy() |
| | | self.config_factory.items = [('app', dummy), ('root', dummy), |
| | | ('registry', dummy), ('request', dummy)] |
| | | shell = DummyShell() |
| | | command.command(shell) |
| | | self.assertTrue(self.config_factory.parser) |
| | | self.assertEqual(self.config_factory.parser.filename, |
| | | '/foo/bar/myapp.ini') |
| | | self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') |
| | | self.assertEqual(shell.env, { |
| | | 'app':dummy, 'root':dummy, 'registry':dummy, 'request':dummy, |
| | | 'root_factory':self.bootstrap.root_factory, |
| | | }) |
| | | self.assertTrue(self.bootstrap.closer.called) |
| | | self.assertTrue(shell.help) |
| | | |
| | | class TestPRoutesCommand(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | |
| | | return PRoutesCommand |
| | | |
| | | def _makeOne(self): |
| | | return self._getTargetClass()('proutes') |
| | | cmd = self._getTargetClass()('proutes') |
| | | cmd.bootstrap = (DummyBootstrap(),) |
| | | cmd.args = ('/foo/bar/myapp.ini#myapp',) |
| | | return cmd |
| | | |
| | | def test_no_routes(self): |
| | | command = self._makeOne() |
| | |
| | | command._get_mapper = lambda *arg: mapper |
| | | L = [] |
| | | command.out = L.append |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L, []) |
| | |
| | | command._get_mapper = lambda *arg:None |
| | | L = [] |
| | | command.out = L.append |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L, []) |
| | |
| | | command._get_mapper = lambda *arg: mapper |
| | | L = [] |
| | | command.out = L.append |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(len(L), 3) |
| | |
| | | command._get_mapper = lambda *arg: mapper |
| | | L = [] |
| | | command.out = L.append |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | command.bootstrap = (DummyBootstrap(registry=registry),) |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(len(L), 3) |
| | |
| | | command._get_mapper = lambda *arg: mapper |
| | | L = [] |
| | | command.out = L.append |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | command.bootstrap = (DummyBootstrap(registry=registry),) |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(len(L), 3) |
| | |
| | | command._get_mapper = lambda *arg: mapper |
| | | L = [] |
| | | command.out = L.append |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp') |
| | | command.bootstrap = (DummyBootstrap(registry=registry),) |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(len(L), 3) |
| | |
| | | from pyramid.urldispatch import RoutesMapper |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | class App: pass |
| | | app = App() |
| | | app.registry = registry |
| | | result = command._get_mapper(app) |
| | | result = command._get_mapper(registry) |
| | | self.assertEqual(result.__class__, RoutesMapper) |
| | | |
| | | class TestPViewsCommand(unittest.TestCase): |
| | |
| | | from pyramid.paster import PViewsCommand |
| | | return PViewsCommand |
| | | |
| | | def _makeOne(self): |
| | | return self._getTargetClass()('pviews') |
| | | def _makeOne(self, registry=None): |
| | | cmd = self._getTargetClass()('pviews') |
| | | cmd.bootstrap = (DummyBootstrap(registry=registry),) |
| | | cmd.args = ('/foo/bar/myapp.ini#myapp',) |
| | | return cmd |
| | | |
| | | def failUnless(self, condition): |
| | | # silence stupid deprecation under Python >= 2.7 |
| | | self.assertTrue(condition) |
| | | def _register_mapper(self, registry, routes): |
| | | from pyramid.interfaces import IRoutesMapper |
| | | mapper = DummyMapper(*routes) |
| | | registry.registerUtility(mapper, IRoutesMapper) |
| | | |
| | | def test__find_view_no_match(self): |
| | | from pyramid.registry import Registry |
| | | registry = Registry() |
| | | self._register_mapper(registry, []) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry) |
| | | result = command._find_view('/a', registry) |
| | | self.assertEqual(result, None) |
| | | |
| | |
| | | (IViewClassifier, IRequest, root_iface), |
| | | IMultiView) |
| | | self._register_mapper(registry, []) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry=registry) |
| | | result = command._find_view('/x', registry) |
| | | self.assertEqual(result, None) |
| | | |
| | |
| | | (IViewClassifier, IRequest, root_iface), |
| | | IView, name='a') |
| | | self._register_mapper(registry, []) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry=registry) |
| | | result = command._find_view('/a', registry) |
| | | self.assertEqual(result, view1) |
| | | |
| | |
| | | (IViewClassifier, IRequest, root_iface), |
| | | IMultiView, name='a') |
| | | self._register_mapper(registry, []) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry=registry) |
| | | result = command._find_view('/a', registry) |
| | | self.assertEqual(result, view) |
| | | |
| | |
| | | routes = [DummyRoute('a', '/a', factory=Factory, matchdict={}), |
| | | DummyRoute('b', '/b', factory=Factory)] |
| | | self._register_mapper(registry, routes) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry=registry) |
| | | result = command._find_view('/a', registry) |
| | | self.assertEqual(result, view) |
| | | |
| | |
| | | routes = [DummyRoute('a', '/a', matchdict={}), |
| | | DummyRoute('b', '/a', matchdict={})] |
| | | self._register_mapper(registry, routes) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry=registry) |
| | | result = command._find_view('/a', registry) |
| | | self.failUnless(IMultiView.providedBy(result)) |
| | | self.assertTrue(IMultiView.providedBy(result)) |
| | | |
| | | def test__find_view_route_multiview(self): |
| | | from zope.interface import Interface |
| | |
| | | routes = [DummyRoute('a', '/a', matchdict={}), |
| | | DummyRoute('b', '/a', matchdict={})] |
| | | self._register_mapper(registry, routes) |
| | | command = self._makeOne() |
| | | command = self._makeOne(registry=registry) |
| | | result = command._find_view('/a', registry) |
| | | self.failUnless(IMultiView.providedBy(result)) |
| | | self.assertTrue(IMultiView.providedBy(result)) |
| | | self.assertEqual(len(result.views), 2) |
| | | self.failUnless((None, view1, None) in result.views) |
| | | self.failUnless((None, view2, None) in result.views) |
| | | self.assertTrue((None, view1, None) in result.views) |
| | | self.assertTrue((None, view2, None) in result.views) |
| | | |
| | | def test__find_multi_routes_all_match(self): |
| | | command = self._makeOne() |
| | |
| | | |
| | | def test_views_command_not_found(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | command._find_view = lambda arg1, arg2: None |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_not_found_url_starts_without_slash(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | command._find_view = lambda arg1, arg2: None |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', 'a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', 'a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_single_view_traversal(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | view = DummyView(context='context', view_name='a') |
| | | command._find_view = lambda arg1, arg2: view |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_single_view_function_traversal(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | def view(): pass |
| | | view.__request_attrs__ = {'context': 'context', 'view_name': 'a'} |
| | | command._find_view = lambda arg1, arg2: view |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_single_view_traversal_with_permission(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | view = DummyView(context='context', view_name='a') |
| | | view.__permission__ = 'test' |
| | | command._find_view = lambda arg1, arg2: view |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_single_view_traversal_with_predicates(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | def predicate(): pass |
| | |
| | | view = DummyView(context='context', view_name='a') |
| | | view.__predicates__ = [predicate] |
| | | command._find_view = lambda arg1, arg2: view |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_single_view_route(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | route = DummyRoute('a', '/a', matchdict={}) |
| | | view = DummyView(context='context', view_name='a', |
| | | matched_route=route, subpath='') |
| | | command._find_view = lambda arg1, arg2: view |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_multi_view_nested(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | view1 = DummyView(context='context', view_name='a1') |
| | |
| | | multiview2 = DummyMultiView(multiview1, context='context', |
| | | view_name='a') |
| | | command._find_view = lambda arg1, arg2: multiview2 |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_single_view_route_with_route_predicates(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | def predicate(): pass |
| | |
| | | view = DummyView(context='context', view_name='a', |
| | | matched_route=route, subpath='') |
| | | command._find_view = lambda arg1, arg2: view |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_multiview(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | view = DummyView(context='context') |
| | |
| | | view.__view_attr__ = 'call' |
| | | multiview = DummyMultiView(view, context='context', view_name='a') |
| | | command._find_view = lambda arg1, arg2: multiview |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_multiview_with_permission(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | view = DummyView(context='context') |
| | |
| | | view.__permission__ = 'test' |
| | | multiview = DummyMultiView(view, context='context', view_name='a') |
| | | command._find_view = lambda arg1, arg2: multiview |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | |
| | | def test_views_command_multiview_with_predicates(self): |
| | | from pyramid.registry import Registry |
| | | command = self._makeOne() |
| | | registry = Registry() |
| | | command = self._makeOne(registry=registry) |
| | | L = [] |
| | | command.out = L.append |
| | | def predicate(): pass |
| | |
| | | view.__predicates__ = [predicate] |
| | | multiview = DummyMultiView(view, context='context', view_name='a') |
| | | command._find_view = lambda arg1, arg2: multiview |
| | | app = DummyApp() |
| | | app.registry = registry |
| | | loadapp = DummyLoadApp(app) |
| | | command.loadapp = (loadapp,) |
| | | command.args = ('/foo/bar/myapp.ini', 'myapp', '/a') |
| | | command.args = ('/foo/bar/myapp.ini#myapp', '/a') |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L[1], 'URL = /a') |
| | |
| | | self.assertEqual(L[4], ' view name: a') |
| | | self.assertEqual(L[8], ' pyramid.tests.test_paster.view.call') |
| | | self.assertEqual(L[9], ' view predicates (predicate = x)') |
| | | |
| | | def _register_mapper(self, registry, routes): |
| | | from pyramid.interfaces import IRoutesMapper |
| | | mapper = DummyMapper(*routes) |
| | | registry.registerUtility(mapper, IRoutesMapper) |
| | | |
| | | class TestGetApp(unittest.TestCase): |
| | | def _callFUT(self, config_file, section_name, loadapp): |
| | |
| | | self.assertEqual(loadapp.section_name, 'myapp') |
| | | self.assertEqual(loadapp.relative_to, os.getcwd()) |
| | | self.assertEqual(result, app) |
| | | |
| | | |
| | | |
| | | def test_it_with_hash(self): |
| | | import os |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | result = self._callFUT('/foo/bar/myapp.ini#myapp', None, loadapp) |
| | | self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') |
| | | self.assertEqual(loadapp.section_name, 'myapp') |
| | | self.assertEqual(loadapp.relative_to, os.getcwd()) |
| | | self.assertEqual(result, app) |
| | | |
| | | def test_it_with_hash_and_name_override(self): |
| | | import os |
| | | app = DummyApp() |
| | | loadapp = DummyLoadApp(app) |
| | | result = self._callFUT('/foo/bar/myapp.ini#myapp', 'yourapp', loadapp) |
| | | self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') |
| | | self.assertEqual(loadapp.section_name, 'yourapp') |
| | | self.assertEqual(loadapp.relative_to, os.getcwd()) |
| | | self.assertEqual(result, app) |
| | | |
| | | class TestBootstrap(unittest.TestCase): |
| | | def _callFUT(self, config_uri, request=None): |
| | | from pyramid.paster import bootstrap |
| | | return bootstrap(config_uri, request) |
| | | |
| | | def setUp(self): |
| | | import pyramid.paster |
| | | self.original_get_app = pyramid.paster.get_app |
| | | self.original_prepare = pyramid.paster.prepare |
| | | self.app = app = DummyApp() |
| | | self.root = root = Dummy() |
| | | |
| | | class DummyGetApp(object): |
| | | def __call__(self, *a, **kw): |
| | | self.a = a |
| | | self.kw = kw |
| | | return app |
| | | self.get_app = pyramid.paster.get_app = DummyGetApp() |
| | | |
| | | class DummyPrepare(object): |
| | | def __call__(self, *a, **kw): |
| | | self.a = a |
| | | self.kw = kw |
| | | return {'root':root, 'closer':lambda: None} |
| | | self.getroot = pyramid.paster.prepare = DummyPrepare() |
| | | |
| | | def tearDown(self): |
| | | import pyramid.paster |
| | | pyramid.paster.get_app = self.original_get_app |
| | | pyramid.paster.prepare = self.original_prepare |
| | | |
| | | def test_it_request_with_registry(self): |
| | | request = DummyRequest({}) |
| | | request.registry = dummy_registry |
| | | result = self._callFUT('/foo/bar/myapp.ini', request) |
| | | self.assertEqual(result['app'], self.app) |
| | | self.assertEqual(result['root'], self.root) |
| | | self.assert_('closer' in result) |
| | | |
| | | class TestPTweensCommand(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.paster import PTweensCommand |
| | | return PTweensCommand |
| | | |
| | | def _makeOne(self): |
| | | cmd = self._getTargetClass()('ptweens') |
| | | cmd.bootstrap = (DummyBootstrap(),) |
| | | cmd.args = ('/foo/bar/myapp.ini#myapp',) |
| | | return cmd |
| | | |
| | | def test_command_no_tweens(self): |
| | | command = self._makeOne() |
| | | command._get_tweens = lambda *arg: None |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual(L, []) |
| | | |
| | | def test_command_implicit_tweens_only(self): |
| | | command = self._makeOne() |
| | | tweens = DummyTweens([('name', 'item')], None) |
| | | command._get_tweens = lambda *arg: tweens |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual( |
| | | L[0], |
| | | '"pyramid.tweens" config value NOT set (implicitly ordered tweens ' |
| | | 'used)') |
| | | |
| | | def test_command_implicit_and_explicit_tweens(self): |
| | | command = self._makeOne() |
| | | tweens = DummyTweens([('name', 'item')], [('name2', 'item2')]) |
| | | command._get_tweens = lambda *arg: tweens |
| | | L = [] |
| | | command.out = L.append |
| | | result = command.command() |
| | | self.assertEqual(result, None) |
| | | self.assertEqual( |
| | | L[0], |
| | | '"pyramid.tweens" config value set (explicitly ordered tweens used)') |
| | | |
| | | def test__get_tweens(self): |
| | | command = self._makeOne() |
| | | registry = DummyRegistry() |
| | | self.assertEqual(command._get_tweens(registry), None) |
| | | |
| | | class DummyTweens(object): |
| | | def __init__(self, implicit, explicit): |
| | | self._implicit = implicit |
| | | self.explicit = explicit |
| | | self.name_to_alias = {} |
| | | def implicit(self): |
| | | return self._implicit |
| | | |
| | | class Dummy: |
| | | pass |
| | | |
| | | class DummyIPShellFactory(object): |
| | | def __call__(self, argv, user_ns=None): |
| | | shell = DummyIPShell() |
| | | shell(user_ns, {}) |
| | | self.shell = shell |
| | | return shell |
| | | |
| | | class DummyIPShell(object): |
| | | IP = Dummy() |
| | | IP.BANNER = 'foo' |
| | | def __call__(self, local_ns, global_ns): |
| | | self.local_ns = local_ns |
| | | self.global_ns = global_ns |
| | | |
| | | def mainloop(self): |
| | | pass |
| | | |
| | | dummy_root = Dummy() |
| | | |
| | | class DummyRegistry(object): |
| | | settings = {} |
| | | def queryUtility(self, iface, default=None, name=''): |
| | | return default |
| | | |
| | | dummy_registry = DummyRegistry() |
| | | |
| | | class DummyShell(object): |
| | | env = {} |
| | | help = '' |
| | | |
| | | def __call__(self, env, help): |
| | | self.env = env |
| | | self.help = help |
| | | |
| | | class DummyInteractor: |
| | | def __call__(self, banner, local): |
| | | self.banner = banner |
| | | self.local = local |
| | | |
| | | class DummyIPShell(object): |
| | | IP = Dummy() |
| | | IP.BANNER = 'foo' |
| | | |
| | | def set_banner(self, banner): |
| | | self.banner = banner |
| | | |
| | | def __call__(self): |
| | | self.called = True |
| | | |
| | | class DummyIPShellFactory(object): |
| | | def __call__(self, **kw): |
| | | self.kw = kw |
| | | self.shell = DummyIPShell() |
| | | return self.shell |
| | | |
| | | class DummyLoadApp: |
| | | def __init__(self, app): |
| | |
| | | class DummyApp: |
| | | def __init__(self): |
| | | self.registry = dummy_registry |
| | | self.threadlocal_manager = DummyThreadLocalManager() |
| | | |
| | | def root_factory(self, environ): |
| | | return dummy_root |
| | | |
| | | class DummyThreadLocalManager: |
| | | def __init__(self): |
| | | self.pushed = [] |
| | | self.popped = [] |
| | | |
| | | def push(self, item): |
| | | self.pushed.append(item) |
| | | |
| | | def pop(self): |
| | | self.popped.append(True) |
| | | |
| | | class DummyMapper(object): |
| | | def __init__(self, *routes): |
| | | self.routes = routes |
| | |
| | | self.views = [(None, view, None) for view in views] |
| | | self.__request_attrs__ = attrs |
| | | |
| | | class DummyConfigParser(object): |
| | | def __init__(self, result): |
| | | self.result = result |
| | | |
| | | def read(self, filename): |
| | | self.filename = filename |
| | | |
| | | def items(self, section): |
| | | self.section = section |
| | | if self.result is None: |
| | | from ConfigParser import NoSectionError |
| | | raise NoSectionError, section |
| | | return self.result |
| | | |
| | | class DummyConfigParserFactory(object): |
| | | items = None |
| | | |
| | | def __call__(self): |
| | | self.parser = DummyConfigParser(self.items) |
| | | return self.parser |
| | | |
| | | class DummyCloser(object): |
| | | def __call__(self): |
| | | self.called = True |
| | | |
| | | class DummyBootstrap(object): |
| | | def __init__(self, app=None, registry=None, request=None, root=None, |
| | | root_factory=None, closer=None): |
| | | self.app = app or DummyApp() |
| | | if registry is None: |
| | | registry = DummyRegistry() |
| | | self.registry = registry |
| | | if request is None: |
| | | request = DummyRequest({}) |
| | | self.request = request |
| | | if root is None: |
| | | root = Dummy() |
| | | self.root = root |
| | | if root_factory is None: |
| | | root_factory = Dummy() |
| | | self.root_factory = root_factory |
| | | if closer is None: |
| | | closer = DummyCloser() |
| | | self.closer = closer |
| | | |
| | | def __call__(self, *a, **kw): |
| | | self.a = a |
| | | self.kw = kw |
| | | return { |
| | | 'app': self.app, |
| | | 'registry': self.registry, |
| | | 'request': self.request, |
| | | 'root': self.root, |
| | | 'root_factory': self.root_factory, |
| | | 'closer': self.closer, |
| | | } |
| | |
| | | |
| | | class TestRendererFromName(unittest.TestCase): |
| | | def setUp(self): |
| | | from zope.deprecation import __show__ |
| | | __show__.off() |
| | | self.config = cleanUp() |
| | | |
| | | def tearDown(self): |
| | | cleanUp() |
| | | |
| | | from zope.deprecation import __show__ |
| | | __show__.on() |
| | | |
| | | def _callFUT(self, path, package=None): |
| | | from pyramid.renderers import renderer_from_name |
| | | return renderer_from_name(path, package) |
| | |
| | | settings = None |
| | | helper = self._makeOne(registry=Dummy) |
| | | self.assertEqual(helper.settings, {}) |
| | | |
| | | def test_settings_registry_name_is_None(self): |
| | | class Dummy(object): |
| | | settings = None |
| | | helper = self._makeOne(registry=Dummy) |
| | | self.assertEqual(helper.name, None) |
| | | self.assertEqual(helper.type, '') |
| | | |
| | | def test_settings_registry_settings_is_not_None(self): |
| | | class Dummy(object): |
| | |
| | | self.assertEqual(response.status, '406 You Lose') |
| | | self.assertEqual(response.body, 'abc') |
| | | |
| | | def test_clone_noargs(self): |
| | | helper = self._makeOne('name', 'package', 'registry') |
| | | cloned_helper = helper.clone() |
| | | self.assertEqual(cloned_helper.name, 'name') |
| | | self.assertEqual(cloned_helper.package, 'package') |
| | | self.assertEqual(cloned_helper.registry, 'registry') |
| | | self.assertFalse(helper is cloned_helper) |
| | | |
| | | def test_clone_allargs(self): |
| | | helper = self._makeOne('name', 'package', 'registry') |
| | | cloned_helper = helper.clone(name='name2', package='package2', |
| | | registry='registry2') |
| | | self.assertEqual(cloned_helper.name, 'name2') |
| | | self.assertEqual(cloned_helper.package, 'package2') |
| | | self.assertEqual(cloned_helper.registry, 'registry2') |
| | | self.assertFalse(helper is cloned_helper) |
| | | |
| | | class TestNullRendererHelper(unittest.TestCase): |
| | | def setUp(self): |
| | | self.config = cleanUp() |
| | | |
| | | def tearDown(self): |
| | | cleanUp() |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.renderers import NullRendererHelper |
| | | return NullRendererHelper(*arg, **kw) |
| | | |
| | | def test_instance_conforms(self): |
| | | from zope.interface.verify import verifyObject |
| | | from pyramid.interfaces import IRendererInfo |
| | | helper = self._makeOne() |
| | | verifyObject(IRendererInfo, helper) |
| | | |
| | | def test_render_view(self): |
| | | helper = self._makeOne() |
| | | self.assertEqual(helper.render_view(None, True, None, None), True) |
| | | |
| | | def test_render(self): |
| | | helper = self._makeOne() |
| | | self.assertEqual(helper.render(True, None, None), True) |
| | | |
| | | def test_render_to_response(self): |
| | | helper = self._makeOne() |
| | | self.assertEqual(helper.render_to_response(True, None, None), True) |
| | | |
| | | def test_clone(self): |
| | | helper = self._makeOne() |
| | | self.assertTrue(helper.clone() is helper) |
| | | |
| | | class Test_render(unittest.TestCase): |
| | | def setUp(self): |
| | | self.config = testing.setUp() |
| | |
| | | request.registry.registerAdapter(adapter, (Foo,), IResponse) |
| | | self.assertEqual(request.is_response(foo), True) |
| | | |
| | | def test_json_incorrect_mimetype(self): |
| | | request = self._makeOne({}) |
| | | self.assertEqual(request.json, None) |
| | | def test_json_body_invalid_json(self): |
| | | request = self._makeOne({'REQUEST_METHOD':'POST'}) |
| | | request.body = '{' |
| | | self.assertRaises(ValueError, getattr, request, 'json_body') |
| | | |
| | | def test_json_correct_mimetype(self): |
| | | request = self._makeOne({}) |
| | | request.content_type = 'application/json' |
| | | def test_json_body_valid_json(self): |
| | | request = self._makeOne({'REQUEST_METHOD':'POST'}) |
| | | request.body = '{"a":1}' |
| | | self.assertEqual(request.json, {'a':1}) |
| | | self.assertEqual(request.json_body, {'a':1}) |
| | | |
| | | def test_json_alternate_charset(self): |
| | | def test_json_body_alternate_charset(self): |
| | | from pyramid.compat import json |
| | | request = self._makeOne({}) |
| | | request.content_type = 'application/json' |
| | | request = self._makeOne({'REQUEST_METHOD':'POST'}) |
| | | request.charset = 'latin-1' |
| | | la = unicode('La Pe\xc3\xb1a', 'utf-8') |
| | | body = json.dumps({'a':la}, encoding='latin-1') |
| | | request.body = body |
| | | self.assertEqual(request.json, {'a':la}) |
| | | self.assertEqual(request.json_body, {'a':la}) |
| | | |
| | | def test_json_body_GET_request(self): |
| | | request = self._makeOne({'REQUEST_METHOD':'GET'}) |
| | | self.assertRaises(ValueError, getattr, request, 'json_body') |
| | | |
| | | class TestRequestDeprecatedMethods(unittest.TestCase): |
| | | def setUp(self): |
| | |
| | | self.assertTrue(hasattr(iface, 'combined')) |
| | | self.assertEqual(iface.combined.__name__, 'routename_combined_IRequest') |
| | | |
| | | def test_it_routename_with_spaces(self): |
| | | # see https://github.com/Pylons/pyramid/issues/232 |
| | | iface = self._callFUT('routename with spaces') |
| | | self.assertEqual(iface.__name__, 'routename with spaces_IRequest') |
| | | self.assertTrue(hasattr(iface, 'combined')) |
| | | self.assertEqual(iface.combined.__name__, |
| | | 'routename with spaces_combined_IRequest') |
| | | |
| | | |
| | | class Test_add_global_response_headers(unittest.TestCase): |
| | | def _callFUT(self, request, headerlist): |
| | | from pyramid.request import add_global_response_headers |
| | |
| | | import unittest |
| | | from pyramid import testing |
| | | |
| | | class TestResponse(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | |
| | | inst = self._getTargetClass()() |
| | | self.assertTrue(IResponse.providedBy(inst)) |
| | | |
| | | class Dummy(object): |
| | | pass |
| | | |
| | | class DummyConfigurator(object): |
| | | def __init__(self): |
| | | self.adapters = [] |
| | | |
| | | def add_response_adapter(self, wrapped, type_or_iface): |
| | | self.adapters.append((wrapped, type_or_iface)) |
| | | |
| | | class DummyVenusian(object): |
| | | def __init__(self): |
| | | self.attached = [] |
| | | |
| | | def attach(self, wrapped, fn, category=None): |
| | | self.attached.append((wrapped, fn, category)) |
| | | |
| | | class TestResponseAdapter(unittest.TestCase): |
| | | def setUp(self): |
| | | registry = Dummy() |
| | | self.config = testing.setUp(registry=registry) |
| | | self.config.begin() |
| | | |
| | | def tearDown(self): |
| | | self.config.end() |
| | | |
| | | def _makeOne(self, *types_or_ifaces): |
| | | from pyramid.response import response_adapter |
| | | return response_adapter(*types_or_ifaces) |
| | | |
| | | def test_register_single(self): |
| | | from zope.interface import Interface |
| | | class IFoo(Interface): pass |
| | | dec = self._makeOne(IFoo) |
| | | def foo(): pass |
| | | config = DummyConfigurator() |
| | | scanner = Dummy() |
| | | scanner.config = config |
| | | dec.register(scanner, None, foo) |
| | | self.assertEqual(config.adapters, [(foo, IFoo)]) |
| | | |
| | | def test_register_multi(self): |
| | | from zope.interface import Interface |
| | | class IFoo(Interface): pass |
| | | class IBar(Interface): pass |
| | | dec = self._makeOne(IFoo, IBar) |
| | | def foo(): pass |
| | | config = DummyConfigurator() |
| | | scanner = Dummy() |
| | | scanner.config = config |
| | | dec.register(scanner, None, foo) |
| | | self.assertEqual(config.adapters, [(foo, IFoo), (foo, IBar)]) |
| | | |
| | | def test___call__(self): |
| | | from zope.interface import Interface |
| | | class IFoo(Interface): pass |
| | | dec = self._makeOne(IFoo) |
| | | dummy_venusian = DummyVenusian() |
| | | dec.venusian = dummy_venusian |
| | | def foo(): pass |
| | | dec(foo) |
| | | self.assertEqual(dummy_venusian.attached, |
| | | [(foo, dec.register, 'pyramid')]) |
| | |
| | | |
| | | class TestRouter(unittest.TestCase): |
| | | def setUp(self): |
| | | testing.setUp() |
| | | from pyramid.threadlocal import get_current_registry |
| | | self.registry = get_current_registry() |
| | | self.config = testing.setUp() |
| | | self.registry = self.config.registry |
| | | |
| | | def tearDown(self): |
| | | testing.tearDown() |
| | |
| | | router = self._makeOne() |
| | | self.assertEqual(router.request_factory, DummyRequestFactory) |
| | | |
| | | def test_tween_factories(self): |
| | | from pyramid.interfaces import ITweens |
| | | from pyramid.config import Tweens |
| | | from pyramid.response import Response |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IResponse |
| | | tweens = Tweens() |
| | | self.registry.registerUtility(tweens, ITweens) |
| | | L = [] |
| | | def tween_factory1(handler, registry): |
| | | L.append((handler, registry)) |
| | | def wrapper(request): |
| | | request.environ['handled'].append('one') |
| | | return handler(request) |
| | | wrapper.name = 'one' |
| | | wrapper.child = handler |
| | | return wrapper |
| | | def tween_factory2(handler, registry): |
| | | L.append((handler, registry)) |
| | | def wrapper(request): |
| | | request.environ['handled'] = ['two'] |
| | | return handler(request) |
| | | wrapper.name = 'two' |
| | | wrapper.child = handler |
| | | return wrapper |
| | | tweens.add_implicit('one', tween_factory1) |
| | | tweens.add_implicit('two', tween_factory2) |
| | | router = self._makeOne() |
| | | self.assertEqual(router.handle_request.name, 'two') |
| | | self.assertEqual(router.handle_request.child.name, 'one') |
| | | self.assertEqual(router.handle_request.child.child.__name__, |
| | | 'handle_request') |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context) |
| | | environ = self._makeEnviron() |
| | | view = DummyView('abc') |
| | | self._registerView(self.config.derive_view(view), '', |
| | | IViewClassifier, None, None) |
| | | start_response = DummyStartResponse() |
| | | def make_response(s): |
| | | return Response(s) |
| | | router.registry.registerAdapter(make_response, (str,), IResponse) |
| | | app_iter = router(environ, start_response) |
| | | self.assertEqual(app_iter, ['abc']) |
| | | self.assertEqual(start_response.status, '200 OK') |
| | | self.assertEqual(environ['handled'], ['two', 'one']) |
| | | |
| | | def test_call_traverser_default(self): |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | |
| | | self._registerTraverserFactory(context) |
| | | environ = self._makeEnviron() |
| | | view = DummyView('abc') |
| | | self._registerView(view, '', IViewClassifier, None, None) |
| | | self._registerView(self.config.derive_view(view), '', IViewClassifier, |
| | | None, None) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | self.assertRaises(ValueError, router, environ, start_response) |
| | |
| | | self._registerTraverserFactory(context) |
| | | environ = self._makeEnviron() |
| | | view = DummyView('abc') |
| | | self._registerView(view, '', IViewClassifier, None, None) |
| | | self._registerView(self.config.derive_view(view), '', |
| | | IViewClassifier, None, None) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | def make_response(s): |
| | |
| | | response.app_iter = ['Hello world'] |
| | | view = DummyView(response) |
| | | environ = self._makeEnviron() |
| | | self._registerView(view, '', IViewClassifier, None, None) |
| | | self._registerView(self.config.derive_view(view), '', |
| | | IViewClassifier, None, None) |
| | | self._registerRootFactory(context) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | |
| | | start_response = DummyStartResponse() |
| | | why = exc_raised(HTTPNotFound, router, environ, start_response) |
| | | self.assertEqual(why[0], 'notfound') |
| | | |
| | | def test_call_view_raises_response_cleared(self): |
| | | from zope.interface import Interface |
| | | from zope.interface import directlyProvides |
| | | from pyramid.interfaces import IExceptionViewClassifier |
| | | class IContext(Interface): |
| | | pass |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IViewClassifier |
| | | context = DummyContext() |
| | | directlyProvides(context, IContext) |
| | | self._registerTraverserFactory(context, subpath=['']) |
| | | def view(context, request): |
| | | request.response.a = 1 |
| | | raise KeyError |
| | | def exc_view(context, request): |
| | | self.assertFalse(hasattr(request.response, 'a')) |
| | | request.response.body = 'OK' |
| | | return request.response |
| | | environ = self._makeEnviron() |
| | | self._registerView(view, '', IViewClassifier, IRequest, IContext) |
| | | self._registerView(exc_view, '', IExceptionViewClassifier, |
| | | IRequest, KeyError) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | itera = router(environ, start_response) |
| | | self.assertEqual(itera, ['OK']) |
| | | |
| | | def test_call_request_has_response_callbacks(self): |
| | | from zope.interface import Interface |
| | |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IRequestFactory |
| | | from pyramid.interfaces import IExceptionViewClassifier |
| | | def rfactory(environ): |
| | | return request |
| | | self.registry.registerUtility(rfactory, IRequestFactory) |
| | |
| | | directlyProvides(context, IContext) |
| | | self._registerTraverserFactory(context, subpath=['']) |
| | | response = DummyResponse() |
| | | response.app_iter = ['OK'] |
| | | view = DummyView(response, raise_exception=RuntimeError) |
| | | environ = self._makeEnviron() |
| | | def exception_view(context, request): |
| | | self.assertEqual(request.exc_info[0], RuntimeError) |
| | | return response |
| | | self._registerView(view, '', IViewClassifier, IRequest, IContext) |
| | | self._registerView(exception_view, '', IExceptionViewClassifier, |
| | | IRequest, RuntimeError) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | self.assertRaises(RuntimeError, router, environ, start_response) |
| | | # ``exception`` must be attached to request even if a suitable |
| | | # exception view cannot be found |
| | | self.assertEqual(request.exception.__class__, RuntimeError) |
| | | |
| | | result = router(environ, start_response) |
| | | self.assertEqual(result, ['OK']) |
| | | # we clean up the exc_info and exception after the request |
| | | self.assertEqual(request.exception, None) |
| | | self.assertEqual(request.exc_info, None) |
| | | |
| | | def test_call_view_raises_exception_view(self): |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IExceptionViewClassifier |
| | |
| | | exception_response = DummyResponse() |
| | | exception_response.app_iter = ["Hello, world"] |
| | | view = DummyView(response, raise_exception=RuntimeError) |
| | | exception_view = DummyView(exception_response) |
| | | def exception_view(context, request): |
| | | self.assertEqual(request.exception.__class__, RuntimeError) |
| | | return exception_response |
| | | environ = self._makeEnviron() |
| | | self._registerView(view, '', IViewClassifier, IRequest, None) |
| | | self._registerView(exception_view, '', IExceptionViewClassifier, |
| | |
| | | start_response = DummyStartResponse() |
| | | result = router(environ, start_response) |
| | | self.assertEqual(result, ["Hello, world"]) |
| | | self.assertEqual(view.request.exception.__class__, RuntimeError) |
| | | |
| | | def test_call_view_raises_super_exception_sub_exception_view(self): |
| | | from pyramid.interfaces import IViewClassifier |
| | |
| | | environ = self._makeEnviron() |
| | | response = DummyResponse() |
| | | view = DummyView(response, raise_exception=RuntimeError) |
| | | self._registerView(view, '', IViewClassifier, IRequest, None) |
| | | |
| | | self._registerView(self.config.derive_view(view), '', |
| | | IViewClassifier, IRequest, None) |
| | | exception_view = DummyView(None) |
| | | self._registerView(exception_view, '', IExceptionViewClassifier, |
| | | self._registerView(self.config.derive_view(exception_view), '', |
| | | IExceptionViewClassifier, |
| | | IRequest, RuntimeError) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | |
| | | import unittest |
| | | |
| | | class TestGetRoot(unittest.TestCase): |
| | | class Test_get_root(unittest.TestCase): |
| | | def _callFUT(self, app, request=None): |
| | | from pyramid.paster import get_root |
| | | from pyramid.scripting import get_root |
| | | return get_root(app, request) |
| | | |
| | | def test_it_norequest(self): |
| | | app = DummyApp() |
| | | app = DummyApp(registry=dummy_registry) |
| | | root, closer = self._callFUT(app) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | | pushed = app.threadlocal_manager.pushed[0] |
| | |
| | | self.assertEqual(len(app.threadlocal_manager.popped), 1) |
| | | |
| | | def test_it_withrequest(self): |
| | | app = DummyApp() |
| | | app = DummyApp(registry=dummy_registry) |
| | | request = DummyRequest({}) |
| | | root, closer = self._callFUT(app, request) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | |
| | | self.assertEqual(len(app.threadlocal_manager.popped), 1) |
| | | |
| | | def test_it_requestfactory_overridden(self): |
| | | app = DummyApp() |
| | | request = Dummy() |
| | | class DummyFactory(object): |
| | | @classmethod |
| | | def blank(cls, path): |
| | | return request |
| | | registry = DummyRegistry(DummyFactory) |
| | | app.registry = registry |
| | | app = DummyApp(registry=dummy_registry) |
| | | root, closer = self._callFUT(app) |
| | | self.assertEqual(len(app.threadlocal_manager.pushed), 1) |
| | | pushed = app.threadlocal_manager.pushed[0] |
| | | self.assertEqual(pushed['request'].environ['path'], '/') |
| | | |
| | | class Test_prepare(unittest.TestCase): |
| | | def _callFUT(self, request=None, registry=None): |
| | | from pyramid.scripting import prepare |
| | | return prepare(request, registry) |
| | | |
| | | def _makeRegistry(self): |
| | | return DummyRegistry(DummyFactory) |
| | | |
| | | def setUp(self): |
| | | from pyramid.threadlocal import manager |
| | | self.manager = manager |
| | | self.default = manager.get() |
| | | |
| | | def test_it_no_valid_apps(self): |
| | | from pyramid.exceptions import ConfigurationError |
| | | self.assertRaises(ConfigurationError, self._callFUT) |
| | | |
| | | def test_it_norequest(self): |
| | | registry = self._makeRegistry() |
| | | info = self._callFUT(registry=registry) |
| | | root, closer = info['root'], info['closer'] |
| | | pushed = self.manager.get() |
| | | self.assertEqual(pushed['registry'], registry) |
| | | self.assertEqual(pushed['request'].registry, registry) |
| | | self.assertEqual(root.a, (pushed['request'],)) |
| | | closer() |
| | | self.assertEqual(self.default, self.manager.get()) |
| | | |
| | | def test_it_withrequest(self): |
| | | request = DummyRequest({}) |
| | | registry = request.registry = self._makeRegistry() |
| | | info = self._callFUT(request=request) |
| | | root, closer = info['root'], info['closer'] |
| | | pushed = self.manager.get() |
| | | self.assertEqual(pushed['request'], request) |
| | | self.assertEqual(pushed['registry'], registry) |
| | | self.assertEqual(pushed['request'].registry, registry) |
| | | self.assertEqual(root.a, (request,)) |
| | | closer() |
| | | self.assertEqual(self.default, self.manager.get()) |
| | | |
| | | def test_it_with_request_and_registry(self): |
| | | request = DummyRequest({}) |
| | | registry = request.registry = self._makeRegistry() |
| | | info = self._callFUT(request=request, registry=registry) |
| | | root, closer = info['root'], info['closer'] |
| | | pushed = self.manager.get() |
| | | self.assertEqual(pushed['request'], request) |
| | | self.assertEqual(pushed['registry'], registry) |
| | | self.assertEqual(pushed['request'].registry, registry) |
| | | self.assertEqual(root.a, (request,)) |
| | | closer() |
| | | self.assertEqual(self.default, self.manager.get()) |
| | | |
| | | class Test__make_request(unittest.TestCase): |
| | | def _callFUT(self, path='/', registry=None): |
| | | from pyramid.scripting import _make_request |
| | | return _make_request(path, registry) |
| | | |
| | | def test_it_with_registry(self): |
| | | request = self._callFUT('/', dummy_registry) |
| | | self.assertEqual(request.environ['path'], '/') |
| | | self.assertEqual(request.registry, dummy_registry) |
| | | |
| | | def test_it_with_no_registry(self): |
| | | from pyramid.config import global_registries |
| | | # keep registry local so that global_registries is cleared after |
| | | registry = DummyRegistry(DummyFactory) |
| | | global_registries.add(registry) |
| | | request = self._callFUT('/hello') |
| | | self.assertEqual(request.environ['path'], '/hello') |
| | | self.assertEqual(request.registry, registry) |
| | | global_registries.empty() |
| | | |
| | | class Dummy: |
| | | pass |
| | | |
| | | dummy_root = Dummy() |
| | | |
| | | class DummyFactory(object): |
| | | @classmethod |
| | | def blank(cls, path): |
| | | req = DummyRequest({'path': path}) |
| | | return req |
| | | |
| | | def __init__(self, *a, **kw): |
| | | self.a = a |
| | | self.kw = kw |
| | | |
| | | class DummyRegistry(object): |
| | | def __init__(self, result=None): |
| | | self.result = result |
| | | def __init__(self, factory=None): |
| | | self.factory = factory |
| | | |
| | | def queryUtility(self, iface, default=None): |
| | | return self.result or default |
| | | return self.factory or default |
| | | |
| | | dummy_registry = DummyRegistry() |
| | | dummy_registry = DummyRegistry(DummyFactory) |
| | | |
| | | class DummyApp: |
| | | def __init__(self): |
| | | self.registry = dummy_registry |
| | | def __init__(self, registry=None): |
| | | self.threadlocal_manager = DummyThreadLocalManager() |
| | | if registry: |
| | | self.registry = registry |
| | | |
| | | def root_factory(self, environ): |
| | | return dummy_root |
| | |
| | | self.assertEqual(settings['reload_templates'], False) |
| | | self.assertEqual(settings['reload_resources'], False) |
| | | |
| | | self.assertEqual(settings['pyramid.debug_authorization'], False) |
| | | self.assertEqual(settings['pyramid.debug_notfound'], False) |
| | | self.assertEqual(settings['pyramid.debug_routematch'], False) |
| | | self.assertEqual(settings['pyramid.reload_templates'], False) |
| | | self.assertEqual(settings['pyramid.reload_resources'], False) |
| | | |
| | | def test_prevent_http_cache(self): |
| | | settings = self._makeOne({}) |
| | | self.assertEqual(settings['prevent_http_cache'], False) |
| | | self.assertEqual(settings['pyramid.prevent_http_cache'], False) |
| | | result = self._makeOne({'prevent_http_cache':'false'}) |
| | | self.assertEqual(result['prevent_http_cache'], False) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], False) |
| | | result = self._makeOne({'prevent_http_cache':'t'}) |
| | | self.assertEqual(result['prevent_http_cache'], True) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], True) |
| | | result = self._makeOne({'prevent_http_cache':'1'}) |
| | | self.assertEqual(result['prevent_http_cache'], True) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], True) |
| | | result = self._makeOne({'pyramid.prevent_http_cache':'t'}) |
| | | self.assertEqual(result['prevent_http_cache'], True) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], True) |
| | | result = self._makeOne({}, {'PYRAMID_PREVENT_HTTP_CACHE':'1'}) |
| | | self.assertEqual(result['prevent_http_cache'], True) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], True) |
| | | result = self._makeOne({'prevent_http_cache':'false', |
| | | 'pyramid.prevent_http_cache':'1'}) |
| | | self.assertEqual(result['prevent_http_cache'], True) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], True) |
| | | result = self._makeOne({'prevent_http_cache':'false', |
| | | 'pyramid.prevent_http_cache':'f'}, |
| | | {'PYRAMID_PREVENT_HTTP_CACHE':'1'}) |
| | | self.assertEqual(result['prevent_http_cache'], True) |
| | | self.assertEqual(result['pyramid.prevent_http_cache'], True) |
| | | |
| | | def test_reload_templates(self): |
| | | settings = self._makeOne({}) |
| | | self.assertEqual(settings['reload_templates'], False) |
| | | self.assertEqual(settings['pyramid.reload_templates'], False) |
| | | result = self._makeOne({'reload_templates':'false'}) |
| | | self.assertEqual(result['reload_templates'], False) |
| | | self.assertEqual(result['pyramid.reload_templates'], False) |
| | | result = self._makeOne({'reload_templates':'t'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | result = self._makeOne({'reload_templates':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | result = self._makeOne({'pyramid.reload_templates':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | result = self._makeOne({}, {'PYRAMID_RELOAD_TEMPLATES':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | result = self._makeOne({'reload_templates':'false'}, |
| | | {'PYRAMID_RELOAD_TEMPLATES':'1'}) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | result = self._makeOne({'reload_templates':'false', |
| | | 'pyramid.reload_templates':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | result = self._makeOne({'reload_templates':'false'}, |
| | | {'PYRAMID_RELOAD_TEMPLATES':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | |
| | | def test_reload_resources(self): |
| | | # alias for reload_assets |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['reload_resources'], False) |
| | | self.assertEqual(result['reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_resources'], False) |
| | | self.assertEqual(result['pyramid.reload_assets'], False) |
| | | result = self._makeOne({'reload_resources':'false'}) |
| | | self.assertEqual(result['reload_resources'], False) |
| | | self.assertEqual(result['reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_resources'], False) |
| | | self.assertEqual(result['pyramid.reload_assets'], False) |
| | | result = self._makeOne({'reload_resources':'t'}) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'reload_resources':'1'}) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'pyramid.reload_resources':'1'}) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({}, {'PYRAMID_RELOAD_RESOURCES':'1'}) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | result = self._makeOne({'reload_resources':'false'}, |
| | | {'PYRAMID_RELOAD_RESOURCES':'1'}) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'reload_resources':'false', |
| | | 'pyramid.reload_resources':'1'}) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'reload_resources':'false', |
| | | 'pyramid.reload_resources':'false'}, |
| | | {'PYRAMID_RELOAD_RESOURCES':'1'}) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | |
| | | def test_reload_assets(self): |
| | | # alias for reload_resources |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['reload_assets'], False) |
| | | self.assertEqual(result['reload_resources'], False) |
| | | self.assertEqual(result['pyramid.reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_resources'], False) |
| | | result = self._makeOne({'reload_assets':'false'}) |
| | | self.assertEqual(result['reload_resources'], False) |
| | | self.assertEqual(result['reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_resources'], False) |
| | | result = self._makeOne({'reload_assets':'t'}) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | result = self._makeOne({'reload_assets':'1'}) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | result = self._makeOne({'pyramid.reload_assets':'1'}) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | result = self._makeOne({}, {'PYRAMID_RELOAD_ASSETS':'1'}) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | result = self._makeOne({'reload_assets':'false'}, |
| | | {'PYRAMID_RELOAD_ASSETS':'1'}) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | result = self._makeOne({'reload_assets':'false', |
| | | 'pyramid.reload_assets':'1'}) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | result = self._makeOne({'reload_assets':'false', |
| | | 'pyramid.reload_assets':'false'}, |
| | | {'PYRAMID_RELOAD_ASSETS':'1'}) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | |
| | | def test_reload_all(self): |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['reload_templates'], False) |
| | | self.assertEqual(result['reload_resources'], False) |
| | | self.assertEqual(result['reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_templates'], False) |
| | | self.assertEqual(result['pyramid.reload_resources'], False) |
| | | self.assertEqual(result['pyramid.reload_assets'], False) |
| | | result = self._makeOne({'reload_all':'false'}) |
| | | self.assertEqual(result['reload_templates'], False) |
| | | self.assertEqual(result['reload_resources'], False) |
| | | self.assertEqual(result['reload_assets'], False) |
| | | self.assertEqual(result['pyramid.reload_templates'], False) |
| | | self.assertEqual(result['pyramid.reload_resources'], False) |
| | | self.assertEqual(result['pyramid.reload_assets'], False) |
| | | result = self._makeOne({'reload_all':'t'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'reload_all':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'pyramid.reload_all':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({}, {'PYRAMID_RELOAD_ALL':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | result = self._makeOne({'reload_all':'false'}, |
| | | {'PYRAMID_RELOAD_ALL':'1'}) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'reload_all':'false', |
| | | 'pyramid.reload_all':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | result = self._makeOne({'reload_all':'false', |
| | | 'pyramid.reload_all':'false'}, |
| | | {'PYRAMID_RELOAD_ALL':'1'}) |
| | | self.assertEqual(result['reload_templates'], True) |
| | | self.assertEqual(result['reload_resources'], True) |
| | | self.assertEqual(result['reload_assets'], True) |
| | | self.assertEqual(result['pyramid.reload_templates'], True) |
| | | self.assertEqual(result['pyramid.reload_resources'], True) |
| | | self.assertEqual(result['pyramid.reload_assets'], True) |
| | | |
| | | def test_debug_authorization(self): |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['debug_authorization'], False) |
| | | self.assertEqual(result['pyramid.debug_authorization'], False) |
| | | result = self._makeOne({'debug_authorization':'false'}) |
| | | self.assertEqual(result['debug_authorization'], False) |
| | | self.assertEqual(result['pyramid.debug_authorization'], False) |
| | | result = self._makeOne({'debug_authorization':'t'}) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | result = self._makeOne({'debug_authorization':'1'}) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | result = self._makeOne({'pyramid.debug_authorization':'1'}) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | result = self._makeOne({}, {'PYRAMID_DEBUG_AUTHORIZATION':'1'}) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | result = self._makeOne({'debug_authorization':'false'}, |
| | | {'PYRAMID_DEBUG_AUTHORIZATION':'1'}) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | result = self._makeOne({'debug_authorization':'false', |
| | | 'pyramid.debug_authorization':'1'}) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | result = self._makeOne({'debug_authorization':'false', |
| | | 'pyramid.debug_authorization':'false'}, |
| | | {'PYRAMID_DEBUG_AUTHORIZATION':'1'}) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | |
| | | def test_debug_notfound(self): |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['debug_notfound'], False) |
| | | self.assertEqual(result['pyramid.debug_notfound'], False) |
| | | result = self._makeOne({'debug_notfound':'false'}) |
| | | self.assertEqual(result['debug_notfound'], False) |
| | | self.assertEqual(result['pyramid.debug_notfound'], False) |
| | | result = self._makeOne({'debug_notfound':'t'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | result = self._makeOne({'debug_notfound':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | result = self._makeOne({'pyramid.debug_notfound':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | result = self._makeOne({}, {'PYRAMID_DEBUG_NOTFOUND':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | result = self._makeOne({'debug_notfound':'false'}, |
| | | {'PYRAMID_DEBUG_NOTFOUND':'1'}) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | result = self._makeOne({'debug_notfound':'false', |
| | | 'pyramid.debug_notfound':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | result = self._makeOne({'debug_notfound':'false', |
| | | 'pyramid.debug_notfound':'false'}, |
| | | {'PYRAMID_DEBUG_NOTFOUND':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | |
| | | def test_debug_routematch(self): |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['debug_routematch'], False) |
| | | self.assertEqual(result['pyramid.debug_routematch'], False) |
| | | result = self._makeOne({'debug_routematch':'false'}) |
| | | self.assertEqual(result['debug_routematch'], False) |
| | | self.assertEqual(result['pyramid.debug_routematch'], False) |
| | | result = self._makeOne({'debug_routematch':'t'}) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | result = self._makeOne({'debug_routematch':'1'}) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | result = self._makeOne({'pyramid.debug_routematch':'1'}) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | result = self._makeOne({}, {'PYRAMID_DEBUG_ROUTEMATCH':'1'}) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | result = self._makeOne({'debug_routematch':'false'}, |
| | | {'PYRAMID_DEBUG_ROUTEMATCH':'1'}) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | result = self._makeOne({'debug_routematch':'false', |
| | | 'pyramid.debug_routematch':'1'}) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | result = self._makeOne({'debug_routematch':'false', |
| | | 'pyramid.debug_routematch':'false'}, |
| | | {'PYRAMID_DEBUG_ROUTEMATCH':'1'}) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | |
| | | def test_debug_templates(self): |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['debug_templates'], False) |
| | | self.assertEqual(result['pyramid.debug_templates'], False) |
| | | result = self._makeOne({'debug_templates':'false'}) |
| | | self.assertEqual(result['debug_templates'], False) |
| | | self.assertEqual(result['pyramid.debug_templates'], False) |
| | | result = self._makeOne({'debug_templates':'t'}) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'debug_templates':'1'}) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'pyramid.debug_templates':'1'}) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({}, {'PYRAMID_DEBUG_TEMPLATES':'1'}) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | result = self._makeOne({'debug_templates':'false'}, |
| | | {'PYRAMID_DEBUG_TEMPLATES':'1'}) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'debug_templates':'false', |
| | | 'pyramid.debug_templates':'1'}) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'debug_templates':'false', |
| | | 'pyramid.debug_templates':'false'}, |
| | | {'PYRAMID_DEBUG_TEMPLATES':'1'}) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | |
| | | def test_debug_all(self): |
| | | result = self._makeOne({}) |
| | |
| | | self.assertEqual(result['debug_routematch'], False) |
| | | self.assertEqual(result['debug_authorization'], False) |
| | | self.assertEqual(result['debug_templates'], False) |
| | | self.assertEqual(result['pyramid.debug_notfound'], False) |
| | | self.assertEqual(result['pyramid.debug_routematch'], False) |
| | | self.assertEqual(result['pyramid.debug_authorization'], False) |
| | | self.assertEqual(result['pyramid.debug_templates'], False) |
| | | result = self._makeOne({'debug_all':'false'}) |
| | | self.assertEqual(result['debug_notfound'], False) |
| | | self.assertEqual(result['debug_routematch'], False) |
| | | self.assertEqual(result['debug_authorization'], False) |
| | | self.assertEqual(result['debug_templates'], False) |
| | | self.assertEqual(result['pyramid.debug_notfound'], False) |
| | | self.assertEqual(result['pyramid.debug_routematch'], False) |
| | | self.assertEqual(result['pyramid.debug_authorization'], False) |
| | | self.assertEqual(result['pyramid.debug_templates'], False) |
| | | result = self._makeOne({'debug_all':'t'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'debug_all':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'pyramid.debug_all':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({}, {'PYRAMID_DEBUG_ALL':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | result = self._makeOne({'debug_all':'false'}, |
| | | {'PYRAMID_DEBUG_ALL':'1'}) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'debug_all':'false', |
| | | 'pyramid.debug_all':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | result = self._makeOne({'debug_all':'false', |
| | | 'pyramid.debug_all':'false'}, |
| | | {'PYRAMID_DEBUG_ALL':'1'}) |
| | | self.assertEqual(result['debug_notfound'], True) |
| | | self.assertEqual(result['debug_routematch'], True) |
| | | self.assertEqual(result['debug_authorization'], True) |
| | | self.assertEqual(result['debug_templates'], True) |
| | | self.assertEqual(result['pyramid.debug_notfound'], True) |
| | | self.assertEqual(result['pyramid.debug_routematch'], True) |
| | | self.assertEqual(result['pyramid.debug_authorization'], True) |
| | | self.assertEqual(result['pyramid.debug_templates'], True) |
| | | |
| | | def test_default_locale_name(self): |
| | | result = self._makeOne({}) |
| | | self.assertEqual(result['default_locale_name'], 'en') |
| | | self.assertEqual(result['pyramid.default_locale_name'], 'en') |
| | | result = self._makeOne({'default_locale_name':'abc'}) |
| | | self.assertEqual(result['default_locale_name'], 'abc') |
| | | self.assertEqual(result['pyramid.default_locale_name'], 'abc') |
| | | result = self._makeOne({'pyramid.default_locale_name':'abc'}) |
| | | self.assertEqual(result['default_locale_name'], 'abc') |
| | | self.assertEqual(result['pyramid.default_locale_name'], 'abc') |
| | | result = self._makeOne({}, {'PYRAMID_DEFAULT_LOCALE_NAME':'abc'}) |
| | | self.assertEqual(result['default_locale_name'], 'abc') |
| | | result = self._makeOne({'default_locale_name':'def'}, |
| | | {'PYRAMID_DEFAULT_LOCALE_NAME':'abc'}) |
| | | self.assertEqual(result['pyramid.default_locale_name'], 'abc') |
| | | result = self._makeOne({'default_locale_name':'def', |
| | | 'pyramid.default_locale_name':'abc'}) |
| | | self.assertEqual(result['default_locale_name'], 'abc') |
| | | self.assertEqual(result['pyramid.default_locale_name'], 'abc') |
| | | result = self._makeOne({'default_locale_name':'def', |
| | | 'pyramid.default_locale_name':'ghi'}, |
| | | {'PYRAMID_DEFAULT_LOCALE_NAME':'abc'}) |
| | | self.assertEqual(result['default_locale_name'], 'abc') |
| | | self.assertEqual(result['pyramid.default_locale_name'], 'abc') |
| | | |
| | | def test_originals_kept(self): |
| | | result = self._makeOne({'a':'i am so a'}) |
| | |
| | | cleanUp() |
| | | |
| | | def _getTargetClass(self): |
| | | from pyramid.view import static |
| | | return static |
| | | from pyramid.static import static_view |
| | | return static_view |
| | | |
| | | def _makeOne(self, path, package_name=None): |
| | | return self._getTargetClass()(path, package_name=package_name) |
| | | def _makeOne(self, path, package_name=None, use_subpath=False): |
| | | return self._getTargetClass()(path, package_name=package_name, |
| | | use_subpath=use_subpath) |
| | | |
| | | def _makeEnviron(self, **extras): |
| | | environ = { |
| | |
| | | environ.update(extras) |
| | | return environ |
| | | |
| | | def test_abspath(self): |
| | | def test_abspath_subpath(self): |
| | | import os.path |
| | | path = os.path.dirname(__file__) |
| | | view = self._makeOne(path) |
| | | view = self._makeOne(path, use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ['__init__.py'] |
| | |
| | | self.assertEqual(request.copied, True) |
| | | self.assertEqual(response.directory, os.path.normcase(path)) |
| | | |
| | | def test_relpath(self): |
| | | def test_relpath_subpath(self): |
| | | path = 'fixtures' |
| | | view = self._makeOne(path) |
| | | view = self._makeOne(path, use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ['__init__.py'] |
| | |
| | | self.assertEqual(response.package_name, 'pyramid.tests') |
| | | self.assertEqual(response.cache_max_age, 3600) |
| | | |
| | | def test_relpath_withpackage(self): |
| | | view = self._makeOne('another:fixtures') |
| | | def test_relpath_notsubpath(self): |
| | | path = 'fixtures' |
| | | view = self._makeOne(path) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ['__init__.py'] |
| | | request.environ = self._makeEnviron() |
| | | response = view(context, request) |
| | | self.assertTrue(not hasattr(request, 'copied')) |
| | | self.assertEqual(response.root_resource, 'fixtures') |
| | | self.assertEqual(response.resource_name, 'fixtures') |
| | | self.assertEqual(response.package_name, 'pyramid.tests') |
| | | self.assertEqual(response.cache_max_age, 3600) |
| | | |
| | | def test_relpath_withpackage_subpath(self): |
| | | view = self._makeOne('another:fixtures', use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ['__init__.py'] |
| | |
| | | self.assertEqual(response.package_name, 'another') |
| | | self.assertEqual(response.cache_max_age, 3600) |
| | | |
| | | def test_relpath_withpackage_name(self): |
| | | view = self._makeOne('fixtures', package_name='another') |
| | | def test_relpath_withpackage_name_subpath(self): |
| | | view = self._makeOne('fixtures', package_name='another', |
| | | use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ['__init__.py'] |
| | |
| | | self.assertEqual(response.package_name, 'another') |
| | | self.assertEqual(response.cache_max_age, 3600) |
| | | |
| | | def test_no_subpath_preserves_path_info_and_script_name(self): |
| | | view = self._makeOne('fixtures', package_name='another') |
| | | def test_no_subpath_preserves_path_info_and_script_name_subpath(self): |
| | | view = self._makeOne('fixtures', package_name='another', |
| | | use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = () |
| | |
| | | self.assertEqual(request.environ['SCRIPT_NAME'], |
| | | '/script_name/path_info') |
| | | |
| | | def test_with_subpath_path_info_ends_with_slash(self): |
| | | view = self._makeOne('fixtures', package_name='another') |
| | | def test_with_subpath_path_info_ends_with_slash_subpath(self): |
| | | view = self._makeOne('fixtures', package_name='another', |
| | | use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ('subpath',) |
| | |
| | | self.assertEqual(request.environ['SCRIPT_NAME'], '/path_info') |
| | | |
| | | def test_with_subpath_original_script_name_preserved(self): |
| | | view = self._makeOne('fixtures', package_name='another') |
| | | view = self._makeOne('fixtures', package_name='another', |
| | | use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ('subpath',) |
| | |
| | | '/scriptname/path_info') |
| | | |
| | | def test_with_subpath_new_script_name_fixes_trailing_slashes(self): |
| | | view = self._makeOne('fixtures', package_name='another') |
| | | view = self._makeOne('fixtures', package_name='another', |
| | | use_subpath=True) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ('sub', 'path') |
| | |
| | | self.assertEqual(inst.registrations, expected) |
| | | |
| | | def test_add_viewname(self): |
| | | from pyramid.security import NO_PERMISSION_REQUIRED |
| | | from pyramid.static import static_view |
| | | config = DummyConfig() |
| | | inst = self._makeOne(config) |
| | |
| | | expected = [('view/', 'anotherpackage:path/', False)] |
| | | self.assertEqual(inst.registrations, expected) |
| | | self.assertEqual(config.route_args, ('view/', 'view/*subpath')) |
| | | self.assertEqual(config.view_kw['permission'], |
| | | '__no_permission_required__') |
| | | self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED) |
| | | self.assertEqual(config.view_kw['view'].__class__, static_view) |
| | | self.assertEqual(config.view_kw['view'].app.cache_max_age, 1) |
| | | |
New file |
| | |
| | | import unittest |
| | | |
| | | class TestTweens(unittest.TestCase): |
| | | def _makeOne(self): |
| | | from pyramid.config import Tweens |
| | | return Tweens() |
| | | |
| | | def test_add_explicit(self): |
| | | tweens = self._makeOne() |
| | | tweens.add_explicit('name', 'factory') |
| | | self.assertEqual(tweens.explicit, [('name', 'factory')]) |
| | | tweens.add_explicit('name2', 'factory2') |
| | | self.assertEqual(tweens.explicit, [('name', 'factory'), |
| | | ('name2', 'factory2')]) |
| | | |
| | | def test_add_implicit_noaliases(self): |
| | | from pyramid.tweens import INGRESS |
| | | tweens = self._makeOne() |
| | | tweens.add_implicit('name', 'factory') |
| | | self.assertEqual(tweens.names, ['name']) |
| | | self.assertEqual(tweens.factories, |
| | | {'name':'factory'}) |
| | | self.assertEqual(tweens.alias_to_name['name'], 'name') |
| | | self.assertEqual(tweens.name_to_alias['name'], 'name') |
| | | self.assertEqual(tweens.order, [(INGRESS, 'name')]) |
| | | self.assertEqual(tweens.ingress_alias_names, ['name']) |
| | | tweens.add_implicit('name2', 'factory2') |
| | | self.assertEqual(tweens.names, ['name', 'name2']) |
| | | self.assertEqual(tweens.factories, |
| | | {'name':'factory', 'name2':'factory2'}) |
| | | self.assertEqual(tweens.alias_to_name['name2'], 'name2') |
| | | self.assertEqual(tweens.name_to_alias['name2'], 'name2') |
| | | self.assertEqual(tweens.order, |
| | | [(INGRESS, 'name'), (INGRESS, 'name2')]) |
| | | self.assertEqual(tweens.ingress_alias_names, ['name', 'name2']) |
| | | tweens.add_implicit('name3', 'factory3', over='name2') |
| | | self.assertEqual(tweens.names, |
| | | ['name', 'name2', 'name3']) |
| | | self.assertEqual(tweens.factories, |
| | | {'name':'factory', 'name2':'factory2', |
| | | 'name3':'factory3'}) |
| | | self.assertEqual(tweens.alias_to_name['name3'], 'name3') |
| | | self.assertEqual(tweens.name_to_alias['name3'], 'name3') |
| | | self.assertEqual(tweens.order, |
| | | [(INGRESS, 'name'), (INGRESS, 'name2'), |
| | | ('name3', 'name2')]) |
| | | self.assertEqual(tweens.ingress_alias_names, ['name', 'name2']) |
| | | |
| | | def test_add_implicit_withaliases(self): |
| | | from pyramid.tweens import INGRESS |
| | | tweens = self._makeOne() |
| | | tweens.add_implicit('name1', 'factory', alias='n1') |
| | | self.assertEqual(tweens.names, ['name1']) |
| | | self.assertEqual(tweens.factories, |
| | | {'name1':'factory'}) |
| | | self.assertEqual(tweens.alias_to_name['n1'], 'name1') |
| | | self.assertEqual(tweens.name_to_alias['name1'], 'n1') |
| | | self.assertEqual(tweens.order, [(INGRESS, 'n1')]) |
| | | self.assertEqual(tweens.ingress_alias_names, ['n1']) |
| | | tweens.add_implicit('name2', 'factory2', alias='n2') |
| | | self.assertEqual(tweens.names, ['name1', 'name2']) |
| | | self.assertEqual(tweens.factories, |
| | | {'name1':'factory', 'name2':'factory2'}) |
| | | self.assertEqual(tweens.alias_to_name['n2'], 'name2') |
| | | self.assertEqual(tweens.name_to_alias['name2'], 'n2') |
| | | self.assertEqual(tweens.order, |
| | | [(INGRESS, 'n1'), (INGRESS, 'n2')]) |
| | | self.assertEqual(tweens.ingress_alias_names, ['n1', 'n2']) |
| | | tweens.add_implicit('name3', 'factory3', alias='n3', over='name2') |
| | | self.assertEqual(tweens.names, |
| | | ['name1', 'name2', 'name3']) |
| | | self.assertEqual(tweens.factories, |
| | | {'name1':'factory', 'name2':'factory2', |
| | | 'name3':'factory3'}) |
| | | self.assertEqual(tweens.alias_to_name['n3'], 'name3') |
| | | self.assertEqual(tweens.name_to_alias['name3'], 'n3') |
| | | self.assertEqual(tweens.order, |
| | | [(INGRESS, 'n1'), (INGRESS, 'n2'), |
| | | ('n3', 'name2')]) |
| | | self.assertEqual(tweens.ingress_alias_names, ['n1', 'n2']) |
| | | |
| | | def test___call___explicit(self): |
| | | tweens = self._makeOne() |
| | | def factory1(handler, registry): |
| | | return handler |
| | | def factory2(handler, registry): |
| | | return '123' |
| | | tweens.explicit = [('name', factory1), ('name', factory2)] |
| | | self.assertEqual(tweens(None, None), '123') |
| | | |
| | | def test___call___implicit(self): |
| | | tweens = self._makeOne() |
| | | def factory1(handler, registry): |
| | | return handler |
| | | def factory2(handler, registry): |
| | | return '123' |
| | | tweens.names = ['name', 'name2'] |
| | | tweens.alias_to_name = {'name':'name', 'name2':'name2'} |
| | | tweens.name_to_alias = {'name':'name', 'name2':'name2'} |
| | | tweens.factories = {'name':factory1, 'name2':factory2} |
| | | self.assertEqual(tweens(None, None), '123') |
| | | |
| | | def test___call___implicit_with_aliasnames_different_than_names(self): |
| | | tweens = self._makeOne() |
| | | def factory1(handler, registry): |
| | | return handler |
| | | def factory2(handler, registry): |
| | | return '123' |
| | | tweens.names = ['name', 'name2'] |
| | | tweens.alias_to_name = {'foo1':'name', 'foo2':'name2'} |
| | | tweens.name_to_alias = {'name':'foo1', 'name2':'foo2'} |
| | | tweens.factories = {'name':factory1, 'name2':factory2} |
| | | self.assertEqual(tweens(None, None), '123') |
| | | |
| | | def test_implicit_ordering_1(self): |
| | | tweens = self._makeOne() |
| | | tweens.add_implicit('name1', 'factory1') |
| | | tweens.add_implicit('name2', 'factory2') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('name2', 'factory2'), |
| | | ('name1', 'factory1'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_2(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | tweens.add_implicit('name1', 'factory1') |
| | | tweens.add_implicit('name2', 'factory2', over=MAIN) |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('name1', 'factory1'), |
| | | ('name2', 'factory2'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_3(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('auth', 'auth_factory', under='browserid') |
| | | add('dbt', 'dbt_factory') |
| | | add('retry', 'retry_factory', over='txnmgr', under='exceptionview') |
| | | add('browserid', 'browserid_factory') |
| | | add('txnmgr', 'txnmgr_factory', under='exceptionview') |
| | | add('exceptionview', 'excview_factory', over=MAIN) |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('dbt', 'dbt_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ('txnmgr', 'txnmgr_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_4(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', over=MAIN) |
| | | add('auth', 'auth_factory', under='browserid') |
| | | add('retry', 'retry_factory', over='txnmgr', under='exceptionview') |
| | | add('browserid', 'browserid_factory') |
| | | add('txnmgr', 'txnmgr_factory', under='exceptionview') |
| | | add('dbt', 'dbt_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('dbt', 'dbt_factory'), |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ('txnmgr', 'txnmgr_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_5(self): |
| | | from pyramid.tweens import MAIN, INGRESS |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', over=MAIN) |
| | | add('auth', 'auth_factory', under=INGRESS) |
| | | add('retry', 'retry_factory', over='txnmgr', under='exceptionview') |
| | | add('browserid', 'browserid_factory', under=INGRESS) |
| | | add('txnmgr', 'txnmgr_factory', under='exceptionview', over=MAIN) |
| | | add('dbt', 'dbt_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('dbt', 'dbt_factory'), |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ('txnmgr', 'txnmgr_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_withaliases(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', alias='e', over=MAIN) |
| | | add('auth', 'auth_factory', under='b') |
| | | add('retry', 'retry_factory', over='t', under='exceptionview') |
| | | add('browserid', 'browserid_factory', alias='b') |
| | | add('txnmgr', 'txnmgr_factory', alias='t', under='exceptionview') |
| | | add('dbt', 'dbt_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('dbt', 'dbt_factory'), |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ('txnmgr', 'txnmgr_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_withaliases2(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', alias='e', over=MAIN) |
| | | add('auth', 'auth_factory', alias='a', under='b') |
| | | add('retry', 'retry_factory', alias='r', over='t', under='e') |
| | | add('browserid', 'browserid_factory', alias='b') |
| | | add('txnmgr', 'txnmgr_factory', alias='t', under='e') |
| | | add('dbt', 'dbt_factory', alias='d') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('dbt', 'dbt_factory'), |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ('txnmgr', 'txnmgr_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_missing_partial(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', over=MAIN) |
| | | add('auth', 'auth_factory', under='browserid') |
| | | add('retry', 'retry_factory', over='txnmgr', under='exceptionview') |
| | | add('browserid', 'browserid_factory') |
| | | add('dbt', 'dbt_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('dbt', 'dbt_factory'), |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_missing_partial2(self): |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('dbt', 'dbt_factory') |
| | | add('auth', 'auth_factory', under='browserid') |
| | | add('retry', 'retry_factory', over='txnmgr', under='exceptionview') |
| | | add('browserid', 'browserid_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('retry', 'retry_factory'), |
| | | ('browserid', 'browserid_factory'), |
| | | ('auth', 'auth_factory'), |
| | | ('dbt', 'dbt_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_missing_partial3(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', over=MAIN) |
| | | add('retry', 'retry_factory', over='txnmgr', under='exceptionview') |
| | | add('browserid', 'browserid_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('browserid', 'browserid_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_missing_partial_with_aliases(self): |
| | | from pyramid.tweens import MAIN |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('exceptionview', 'excview_factory', alias='e', over=MAIN) |
| | | add('retry', 'retry_factory', over='txnmgr', under='e') |
| | | add('browserid', 'browserid_factory') |
| | | self.assertEqual(tweens.implicit(), |
| | | [ |
| | | ('browserid', 'browserid_factory'), |
| | | ('exceptionview', 'excview_factory'), |
| | | ('retry', 'retry_factory'), |
| | | ]) |
| | | |
| | | def test_implicit_ordering_conflict_direct(self): |
| | | from pyramid.tweens import CyclicDependencyError |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('browserid', 'browserid_factory') |
| | | add('auth', 'auth_factory', over='browserid', under='browserid') |
| | | self.assertRaises(CyclicDependencyError, tweens.implicit) |
| | | |
| | | def test_implicit_ordering_conflict_indirect(self): |
| | | from pyramid.tweens import CyclicDependencyError |
| | | tweens = self._makeOne() |
| | | add = tweens.add_implicit |
| | | add('browserid', 'browserid_factory') |
| | | add('auth', 'auth_factory', over='browserid') |
| | | add('dbt', 'dbt_factory', under='browserid', over='auth') |
| | | self.assertRaises(CyclicDependencyError, tweens.implicit) |
| | | |
| | | class TestCyclicDependencyError(unittest.TestCase): |
| | | def _makeOne(self, cycles): |
| | | from pyramid.tweens import CyclicDependencyError |
| | | return CyclicDependencyError(cycles) |
| | | |
| | | def test___str__(self): |
| | | exc = self._makeOne({'a':['c', 'd'], 'c':['a']}) |
| | | result = str(exc) |
| | | self.assertTrue("'a' sorts over ['c', 'd']" in result) |
| | | self.assertTrue("'c' sorts over ['a']" in result) |
| | | |
| | |
| | | self.assertEqual(typ.package, None) |
| | | self.assertEqual(typ.package_name, None) |
| | | |
| | | class Test_WeakOrderedSet(unittest.TestCase): |
| | | def _makeOne(self): |
| | | from pyramid.config import WeakOrderedSet |
| | | return WeakOrderedSet() |
| | | |
| | | def test_ctor(self): |
| | | wos = self._makeOne() |
| | | self.assertEqual(len(wos), 0) |
| | | self.assertEqual(wos.last, None) |
| | | |
| | | def test_add_item(self): |
| | | wos = self._makeOne() |
| | | reg = Dummy() |
| | | wos.add(reg) |
| | | self.assertEqual(list(wos), [reg]) |
| | | self.assert_(reg in wos) |
| | | self.assertEqual(wos.last, reg) |
| | | |
| | | def test_add_multiple_items(self): |
| | | wos = self._makeOne() |
| | | reg1 = Dummy() |
| | | reg2 = Dummy() |
| | | wos.add(reg1) |
| | | wos.add(reg2) |
| | | self.assertEqual(len(wos), 2) |
| | | self.assertEqual(list(wos), [reg1, reg2]) |
| | | self.assert_(reg1 in wos) |
| | | self.assert_(reg2 in wos) |
| | | self.assertEqual(wos.last, reg2) |
| | | |
| | | def test_add_duplicate_items(self): |
| | | wos = self._makeOne() |
| | | reg = Dummy() |
| | | wos.add(reg) |
| | | wos.add(reg) |
| | | self.assertEqual(len(wos), 1) |
| | | self.assertEqual(list(wos), [reg]) |
| | | self.assert_(reg in wos) |
| | | self.assertEqual(wos.last, reg) |
| | | |
| | | def test_weakref_removal(self): |
| | | wos = self._makeOne() |
| | | reg = Dummy() |
| | | wos.add(reg) |
| | | wos.remove(reg) |
| | | self.assertEqual(len(wos), 0) |
| | | self.assertEqual(list(wos), []) |
| | | self.assertEqual(wos.last, None) |
| | | |
| | | def test_last_updated(self): |
| | | wos = self._makeOne() |
| | | reg = Dummy() |
| | | reg2 = Dummy() |
| | | wos.add(reg) |
| | | wos.add(reg2) |
| | | wos.remove(reg2) |
| | | self.assertEqual(len(wos), 1) |
| | | self.assertEqual(list(wos), [reg]) |
| | | self.assertEqual(wos.last, reg) |
| | | |
| | | def test_empty(self): |
| | | wos = self._makeOne() |
| | | reg = Dummy() |
| | | reg2 = Dummy() |
| | | wos.add(reg) |
| | | wos.add(reg2) |
| | | wos.empty() |
| | | self.assertEqual(len(wos), 0) |
| | | self.assertEqual(list(wos), []) |
| | | self.assertEqual(wos.last, None) |
| | | |
| | | class Dummy(object): |
| | | pass |
| | |
| | | secure=True) |
| | | self.assertEqual(iterable, ()) |
| | | |
| | | def test_call_view_returns_iresponse_adaptable(self): |
| | | from pyramid.response import Response |
| | | request = self._makeRequest() |
| | | context = self._makeContext() |
| | | view = make_view('123') |
| | | self._registerView(request.registry, view, 'registered') |
| | | def str_response(s): |
| | | return Response(s) |
| | | request.registry.registerAdapter(str_response, (str,), IResponse) |
| | | iterable = self._callFUT(context, request, name='registered', |
| | | secure=True) |
| | | self.assertEqual(iterable, ['123']) |
| | | |
| | | def test_call_view_registered_insecure_no_call_permissive(self): |
| | | context = self._makeContext() |
| | | request = self._makeRequest() |
| | |
| | | self.assertEqual(len(settings), 1) |
| | | self.assertEqual(settings[0]['renderer'], {'a':1}) |
| | | |
| | | def test_call_with_renderer_IRendererInfo(self): |
| | | # see https://github.com/Pylons/pyramid/pull/234 |
| | | from pyramid.interfaces import IRendererInfo |
| | | import pyramid.tests |
| | | outerself = self |
| | | class DummyRendererHelper(object): |
| | | implements(IRendererInfo) |
| | | name = 'fixtures/minimal.pt' |
| | | package = pyramid.tests |
| | | def clone(self, name=None, package=None, registry=None): |
| | | outerself.assertEqual(name, self.name) |
| | | outerself.assertEqual(package, self.package) |
| | | outerself.assertEqual(registry, context.config.registry) |
| | | self.cloned = True |
| | | return self |
| | | renderer_helper = DummyRendererHelper() |
| | | decorator = self._makeOne(renderer=renderer_helper) |
| | | venusian = DummyVenusian() |
| | | decorator.venusian = venusian |
| | | def foo(): pass |
| | | wrapped = decorator(foo) |
| | | self.assertTrue(wrapped is foo) |
| | | context = DummyVenusianContext() |
| | | settings = call_venusian(venusian, context) |
| | | self.assertEqual(len(settings), 1) |
| | | renderer = settings[0]['renderer'] |
| | | self.assertTrue(renderer is renderer_helper) |
| | | self.assertTrue(renderer.cloned) |
| | | |
| | | class Test_append_slash_notfound_view(BaseTest, unittest.TestCase): |
| | | def _callFUT(self, context, request): |
| | | from pyramid.view import append_slash_notfound_view |
| | |
| | | result = self._callFUT(module) |
| | | self.assertEqual(result, False) |
| | | |
| | | class Test_static(unittest.TestCase): |
| | | def setUp(self): |
| | | from zope.deprecation import __show__ |
| | | __show__.off() |
| | | |
| | | def tearDown(self): |
| | | from zope.deprecation import __show__ |
| | | __show__.on() |
| | | |
| | | def _getTargetClass(self): |
| | | from pyramid.view import static |
| | | return static |
| | | |
| | | def _makeOne(self, path, package_name=None): |
| | | return self._getTargetClass()(path, package_name=package_name) |
| | | |
| | | def _makeEnviron(self, **extras): |
| | | environ = { |
| | | 'wsgi.url_scheme':'http', |
| | | 'wsgi.version':(1,0), |
| | | 'SERVER_NAME':'localhost', |
| | | 'SERVER_PORT':'8080', |
| | | 'REQUEST_METHOD':'GET', |
| | | } |
| | | environ.update(extras) |
| | | return environ |
| | | |
| | | |
| | | def test_relpath_subpath(self): |
| | | path = 'fixtures' |
| | | view = self._makeOne(path) |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | request.subpath = ['__init__.py'] |
| | | request.environ = self._makeEnviron() |
| | | response = view(context, request) |
| | | self.assertEqual(request.copied, True) |
| | | self.assertEqual(response.root_resource, 'fixtures') |
| | | self.assertEqual(response.resource_name, 'fixtures') |
| | | self.assertEqual(response.package_name, 'pyramid.tests') |
| | | self.assertEqual(response.cache_max_age, 3600) |
| | | |
| | | class ExceptionResponse(Exception): |
| | | status = '404 Not Found' |
| | | app_iter = ['Not Found'] |
| | |
| | | |
| | | class DummyRequest: |
| | | exception = None |
| | | |
| | | def __init__(self, environ=None): |
| | | if environ is None: |
| | | environ = {} |
| | | self.environ = environ |
| | | |
| | | def get_response(self, application): |
| | | return application |
| | | |
| | | def copy(self): |
| | | self.copied = True |
| | | return self |
| | | |
| | | from pyramid.interfaces import IResponse |
| | | from zope.interface import implements |
| | |
| | | def __init__(self): |
| | | self.config = DummyConfig() |
| | | |
| | | def call_venusian(venusian): |
| | | context = DummyVenusianContext() |
| | | def call_venusian(venusian, context=None): |
| | | if context is None: |
| | | context = DummyVenusianContext() |
| | | for wrapped, callback, category in venusian.attachments: |
| | | callback(context, None, None) |
| | | return context.config.settings |
New file |
| | |
| | | import venusian |
| | | |
| | | def foo(wrapped): |
| | | def bar(scanner, name, wrapped): |
| | | scanner.config.a = scanner.a |
| | | venusian.attach(wrapped, bar) |
| | | return wrapped |
| | | |
| | | @foo |
| | | def hello(): |
| | | pass |
| | | |
| | | hello() # appease coverage |
| | | |
New file |
| | |
| | | import sys |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.interfaces import IExceptionViewClassifier |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import ITweens |
| | | |
| | | from zope.interface import providedBy |
| | | from zope.interface import implements |
| | | |
| | | def excview_tween_factory(handler, registry): |
| | | """ A :term:`tween` factory which produces a tween that catches an |
| | | exception raised by downstream tweens (or the main Pyramid request |
| | | handler) and, if possible, converts it into a Response using an |
| | | :term:`exception view`.""" |
| | | adapters = registry.adapters |
| | | |
| | | def excview_tween(request): |
| | | attrs = request.__dict__ |
| | | try: |
| | | response = handler(request) |
| | | except Exception, exc: |
| | | # WARNING: do not assign the result of sys.exc_info() to a |
| | | # local var here, doing so will cause a leak |
| | | attrs['exc_info'] = sys.exc_info() |
| | | attrs['exception'] = exc |
| | | # clear old generated request.response, if any; it may |
| | | # have been mutated by the view, and its state is not |
| | | # sane (e.g. caching headers) |
| | | if 'response' in attrs: |
| | | del attrs['response'] |
| | | request_iface = attrs['request_iface'] |
| | | provides = providedBy(exc) |
| | | for_ = (IExceptionViewClassifier, request_iface.combined, provides) |
| | | view_callable = adapters.lookup(for_, IView, default=None) |
| | | if view_callable is None: |
| | | raise |
| | | response = view_callable(exc, request) |
| | | finally: |
| | | # prevent leakage (wrt exc_info) |
| | | if 'exc_info' in attrs: |
| | | del attrs['exc_info'] |
| | | if 'exception' in attrs: |
| | | del attrs['exception'] |
| | | |
| | | return response |
| | | |
| | | return excview_tween |
| | | |
| | | class CyclicDependencyError(Exception): |
| | | def __init__(self, cycles): |
| | | self.cycles = cycles |
| | | |
| | | def __str__(self): |
| | | L = [] |
| | | cycles = self.cycles |
| | | for cycle in cycles: |
| | | dependent = cycle |
| | | dependees = cycles[cycle] |
| | | L.append('%r sorts over %r' % (dependent, dependees)) |
| | | msg = 'Implicit tween ordering cycle:' + '; '.join(L) |
| | | return msg |
| | | |
| | | class Tweens(object): |
| | | implements(ITweens) |
| | | def __init__(self): |
| | | self.explicit = [] |
| | | self.names = [] |
| | | self.factories = {} |
| | | self.order = [] |
| | | self.ingress_alias_names = [] |
| | | self.alias_to_name = {INGRESS:INGRESS, MAIN:MAIN} |
| | | self.name_to_alias = {INGRESS:INGRESS, MAIN:MAIN} |
| | | |
| | | def add_explicit(self, name, factory): |
| | | self.explicit.append((name, factory)) |
| | | |
| | | def add_implicit(self, name, factory, alias=None, under=None, over=None): |
| | | if alias is None: |
| | | alias = name |
| | | self.alias_to_name[alias] = name |
| | | self.name_to_alias[name] = alias |
| | | self.names.append(name) |
| | | self.factories[name] = factory |
| | | if under is None and over is None: |
| | | under = INGRESS |
| | | self.ingress_alias_names.append(alias) |
| | | if under is not None: |
| | | self.order.append((under, alias)) |
| | | if over is not None: |
| | | self.order.append((alias, over)) |
| | | |
| | | def implicit(self): |
| | | order = [(INGRESS, MAIN)] |
| | | roots = [] |
| | | graph = {} |
| | | has_order = {} |
| | | aliases = [INGRESS, MAIN] |
| | | ingress_alias_names = self.ingress_alias_names[:] |
| | | |
| | | for name in self.names: |
| | | aliases.append(self.name_to_alias[name]) |
| | | |
| | | for a, b in self.order: |
| | | # try to convert both a and b to an alias |
| | | a = self.name_to_alias.get(a, a) |
| | | b = self.name_to_alias.get(b, b) |
| | | order.append((a, b)) |
| | | |
| | | def add_node(node): |
| | | if not graph.has_key(node): |
| | | roots.append(node) |
| | | graph[node] = [0] # 0 = number of arcs coming into this node |
| | | |
| | | def add_arc(fromnode, tonode): |
| | | graph[fromnode].append(tonode) |
| | | graph[tonode][0] += 1 |
| | | if tonode in roots: |
| | | roots.remove(tonode) |
| | | |
| | | # remove ordering information that mentions unknown names/aliases |
| | | for pos, (first, second) in enumerate(order): |
| | | has_first = first in aliases |
| | | has_second = second in aliases |
| | | if (not has_first) or (not has_second): |
| | | order[pos] = None, None |
| | | else: |
| | | has_order[first] = has_order[second] = True |
| | | |
| | | for alias in aliases: |
| | | # any alias that doesn't have an ordering after we detect all |
| | | # nodes with orders should get an ordering relative to INGRESS, |
| | | # as if it were added with no under or over in add_implicit |
| | | if (not alias in has_order) and (alias not in (INGRESS, MAIN)): |
| | | order.append((INGRESS, alias)) |
| | | ingress_alias_names.append(alias) |
| | | add_node(alias) |
| | | |
| | | for a, b in order: |
| | | if a is not None and b is not None: # deal with removed orders |
| | | add_arc(a, b) |
| | | |
| | | sorted_aliases = [] |
| | | |
| | | while roots: |
| | | root = roots.pop(0) |
| | | sorted_aliases.append(root) |
| | | children = graph[root][1:] |
| | | for child in children: |
| | | arcs = graph[child][0] |
| | | arcs -= 1 |
| | | graph[child][0] = arcs |
| | | if arcs == 0: |
| | | roots.insert(0, child) |
| | | del graph[root] |
| | | |
| | | if graph: |
| | | # loop in input |
| | | cycledeps = {} |
| | | for k, v in graph.items(): |
| | | cycledeps[k] = v[1:] |
| | | raise CyclicDependencyError(cycledeps) |
| | | |
| | | result = [] |
| | | |
| | | for alias in sorted_aliases: |
| | | if alias not in (MAIN, INGRESS): |
| | | name = self.alias_to_name.get(alias, alias) |
| | | result.append((name, self.factories[name])) |
| | | |
| | | return result |
| | | |
| | | def __call__(self, handler, registry): |
| | | if self.explicit: |
| | | use = self.explicit |
| | | else: |
| | | use = self.implicit() |
| | | for name, factory in use[::-1]: |
| | | handler = factory(handler, registry) |
| | | return handler |
| | | |
| | | def tween_factory_name(factory): |
| | | if (hasattr(factory, '__name__') and hasattr(factory, '__module__')): |
| | | # function or class |
| | | name = '.'.join([factory.__module__, factory.__name__]) |
| | | elif hasattr(factory, '__module__'): |
| | | # instance |
| | | name = '.'.join([factory.__module__, factory.__class__.__name__, |
| | | str(id(factory))]) |
| | | else: |
| | | raise ConfigurationError( |
| | | 'A tween factory must be a class, an instance, or a function; ' |
| | | '%s is not a suitable tween factory' % factory) |
| | | return name |
| | | |
| | | MAIN = 'MAIN' |
| | | INGRESS = 'INGRESS' |
| | | EXCVIEW = 'excview' |
| | | |
| | |
| | | ``/foo/1``. |
| | | |
| | | If the 'current route' has the route pattern ``/foo/{page}`` and the |
| | | current current url path is ``/foo/1``, the matchdict will be |
| | | current url path is ``/foo/1``, the matchdict will be |
| | | ``{'page':'1'}``. The result of ``current_route_url(request, page='2')`` |
| | | in this situation will be ``/foo/2``. |
| | | |
| | |
| | | from pyramid.interfaces import IRoutesMapper |
| | | from pyramid.interfaces import IRoute |
| | | |
| | | from pyramid.compat import all |
| | | from pyramid.encode import url_quote |
| | | from pyramid.exceptions import URLDecodeError |
| | | from pyramid.traversal import traversal_path |
| | | from pyramid.traversal import quote_path_segment |
| | | |
| | | |
| | | _marker = object() |
| | | |
| | |
| | | import pkg_resources |
| | | import sys |
| | | import weakref |
| | | |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.path import package_of |
| | |
| | | return self._zope_dottedname_style(dotted) |
| | | return dotted |
| | | |
| | | class WeakOrderedSet(object): |
| | | """ Maintain a set of items. |
| | | |
| | | Each item is stored as a weakref to avoid extending their lifetime. |
| | | |
| | | The values may be iterated over or the last item added may be |
| | | accessed via the ``last`` property. |
| | | |
| | | If items are added more than once, the most recent addition will |
| | | be remembered in the order: |
| | | |
| | | order = WeakOrderedSet() |
| | | order.add('1') |
| | | order.add('2') |
| | | order.add('1') |
| | | |
| | | list(order) == ['2', '1'] |
| | | order.last == '1' |
| | | """ |
| | | |
| | | def __init__(self): |
| | | self._items = {} |
| | | self._order = [] |
| | | |
| | | def add(self, item): |
| | | """ Add an item to the set.""" |
| | | oid = id(item) |
| | | if oid in self._items: |
| | | self._order.remove(oid) |
| | | self._order.append(oid) |
| | | return |
| | | ref = weakref.ref(item, lambda x: self.remove(item)) |
| | | self._items[oid] = ref |
| | | self._order.append(oid) |
| | | |
| | | def remove(self, item): |
| | | """ Remove an item from the set.""" |
| | | oid = id(item) |
| | | if oid in self._items: |
| | | del self._items[oid] |
| | | self._order.remove(oid) |
| | | |
| | | def empty(self): |
| | | """ Clear all objects from the set.""" |
| | | self._items = {} |
| | | self._order = [] |
| | | |
| | | def __len__(self): |
| | | return len(self._order) |
| | | |
| | | def __contains__(self, item): |
| | | oid = id(item) |
| | | return oid in self._items |
| | | |
| | | def __iter__(self): |
| | | return (self._items[oid]() for oid in self._order) |
| | | |
| | | @property |
| | | def last(self): |
| | | if self._order: |
| | | oid = self._order[-1] |
| | | return self._items[oid]() |
| | | |
| | |
| | | from zope.interface import providedBy |
| | | from zope.deprecation import deprecated |
| | | |
| | | from pyramid.interfaces import IResponse |
| | | from pyramid.interfaces import IRoutesMapper |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.interfaces import IRendererInfo |
| | | |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.httpexceptions import default_exceptionresponse_view |
| | | from pyramid.path import caller_package |
| | | from pyramid.renderers import RendererHelper |
| | | from pyramid.static import static_view |
| | | from pyramid.threadlocal import get_current_registry |
| | |
| | | # fallout. |
| | | init_mimetypes(mimetypes) |
| | | |
| | | # Nasty BW compat hack: dont yet deprecate this (ever?) |
| | | class static(static_view): # only subclass for purposes of autodoc |
| | | __doc__ = static_view.__doc__ |
| | | |
| | | _marker = object() |
| | | |
| | | class static(static_view): |
| | | """ Backwards compatibility alias for |
| | | :class:`pyramid.static.static_view`; it overrides that class' constructor |
| | | to pass ``use_subpath=True`` by default. This class is deprecated as of |
| | | :app:`Pyramid` 1.1. Use :class:`pyramid.static.static_view` instead |
| | | (probably with a ``use_subpath=True`` argument). |
| | | """ |
| | | def __init__(self, root_dir, cache_max_age=3600, package_name=None): |
| | | if package_name is None: |
| | | package_name = caller_package().__name__ |
| | | static_view.__init__(self, root_dir, cache_max_age=cache_max_age, |
| | | package_name=package_name, use_subpath=True) |
| | | |
| | | deprecated( |
| | | '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.') |
| | | |
| | | def render_view_to_response(context, request, name='', secure=True): |
| | | """ Call the :term:`view callable` configured with a :term:`view |
| | |
| | | response = render_view_to_response(context, request, name, secure) |
| | | if response is None: |
| | | return None |
| | | try: |
| | | reg = request.registry |
| | | except AttributeError: |
| | | reg = get_current_registry() |
| | | response = reg.queryAdapterOrSelf(response, IResponse) |
| | | return response.app_iter |
| | | |
| | | def render_view(context, request, name='', secure=True): |
| | |
| | | renderer = RendererHelper(name=renderer, |
| | | package=info.module, |
| | | registry=context.config.registry) |
| | | elif IRendererInfo.providedBy(renderer): |
| | | # create a new rendererinfo to clear out old registry on a |
| | | # rescan, see https://github.com/Pylons/pyramid/pull/234 |
| | | renderer = renderer.clone(name=renderer.name, |
| | | package=info.module, |
| | | registry=context.config.registry) |
| | | settings['renderer'] = renderer |
| | | context.config.add_view(view=ob, **settings) |
| | | |
| | |
| | | from pyramid.compat import wraps |
| | | from functools import wraps |
| | | from pyramid.request import call_app_with_subpath_as_path_info |
| | | |
| | | def wsgiapp(wrapped): |
| | |
| | | install_requires.append('simplejson') |
| | | |
| | | setup(name='pyramid', |
| | | version='1.1a4', |
| | | version='1.1.1dev', |
| | | description=('The Pyramid web application development framework, a ' |
| | | 'Pylons project'), |
| | | long_description=README + '\n\n' + CHANGES, |
| | |
| | | pshell=pyramid.paster:PShellCommand |
| | | proutes=pyramid.paster:PRoutesCommand |
| | | pviews=pyramid.paster:PViewsCommand |
| | | ptweens=pyramid.paster:PTweensCommand |
| | | [console_scripts] |
| | | bfg2pyramid = pyramid.fixers.fix_bfg_imports:main |
| | | """ |
| | |
| | | repoze.sphinx.autointerface |
| | | virtualenv |
| | | nose |
| | | coverage |
| | | coverage==3.4 |
| | | nosexcover |
| | | |
| | | # we separate coverage into its own testenv because a) "last run wins" wrt |