summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/index.rst1
-rw-r--r--docs/latexindex.rst1
-rw-r--r--docs/narr/environment.rst17
-rw-r--r--docs/narr/events.rst62
-rw-r--r--docs/narr/handlers.rst277
-rw-r--r--docs/narr/i18n.rst10
-rw-r--r--docs/narr/security.rst26
-rw-r--r--docs/narr/testing.rst40
-rw-r--r--docs/narr/views.rst5
9 files changed, 372 insertions, 67 deletions
diff --git a/docs/index.rst b/docs/index.rst
index 0dc476e46..3e70e1231 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -45,6 +45,7 @@ Narrative documentation in chapter form explaining how to use
narr/renderers
narr/templates
narr/viewconfig
+ narr/handlers
narr/resources
narr/assets
narr/webob
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 00f177e5c..2e6be2f3f 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -38,6 +38,7 @@ Narrative Documentation
narr/renderers
narr/templates
narr/viewconfig
+ narr/handlers
narr/resources
narr/assets
narr/webob
diff --git a/docs/narr/environment.rst b/docs/narr/environment.rst
index 7caa1dcc6..7b7946aae 100644
--- a/docs/narr/environment.rst
+++ b/docs/narr/environment.rst
@@ -38,10 +38,11 @@ application-specific configuration settings.
Reloading Templates
-------------------
-When this value is true, reload templates without a restart, so you can see
-changes to templates take effect immediately during development. This flag
-is meaningful to Chameleon and Mako templates, as well as most third-party
-template rendering extensions.
+When this value is true, templates are automatically reloaded whenever
+they are modified without restarting the application, so you can see
+changes to templates take effect immediately during development. This
+flag is meaningful to Chameleon and Mako templates, as well as most
+third-party template rendering extensions.
+---------------------------------+-----------------------------+
| Environment Variable Name | Config File Setting Name |
@@ -335,6 +336,14 @@ with ``reload_``). on in one fell swoop, you can use
affect settings that do not start with ``reload_*`` such as
``debug_notfound``.
+.. note::
+ Specifying configuration settings via environment variables is generally
+ most useful during development, where you may wish to augment or
+ override the more permanent settings in the configuration file.
+ This is useful because many of the reload and debug settings may
+ have performance or security (i.e., disclosure) implications
+ that make them undesirable in a production environment.
+
.. index::
single: reload_templates
single: reload_assets
diff --git a/docs/narr/events.rst b/docs/narr/events.rst
index 06b30883f..90966a730 100644
--- a/docs/narr/events.rst
+++ b/docs/narr/events.rst
@@ -38,49 +38,51 @@ you'll need to use the
need to use the :func:`pyramid.events.subscriber` decorator to decorate a
function found via a :term:`scan`.
-.. topic:: Configuring an Event Listener Imperatively
+Configuring an Event Listener Imperatively
+------------------------------------------
- You can imperatively configure a subscriber function to be called
- for some event type via the
- :meth:`pyramid.config.Configurator.add_subscriber`
- method (see also :term:`Configurator`):
+You can imperatively configure a subscriber function to be called
+for some event type via the
+:meth:`pyramid.config.Configurator.add_subscriber`
+method (see also :term:`Configurator`):
- .. code-block:: python
- :linenos:
+.. code-block:: python
+ :linenos:
- from pyramid.events import NewRequest
+ from pyramid.events import NewRequest
- from subscribers import mysubscriber
+ from subscribers import mysubscriber
- # "config" below is assumed to be an instance of a
- # pyramid.config.Configurator object
+ # "config" below is assumed to be an instance of a
+ # pyramid.config.Configurator object
- config.add_subscriber(mysubscriber, NewRequest)
+ config.add_subscriber(mysubscriber, NewRequest)
- The first argument to
- :meth:`pyramid.config.Configurator.add_subscriber` is the
- subscriber function (or a :term:`dotted Python name` which refers
- to a subscriber callable); the second argument is the event type.
+The first argument to
+:meth:`pyramid.config.Configurator.add_subscriber` is the
+subscriber function (or a :term:`dotted Python name` which refers
+to a subscriber callable); the second argument is the event type.
-.. topic:: Configuring an Event Listener Using a Decorator
+Configuring an Event Listener Using a Decorator
+-----------------------------------------------
- You can configure a subscriber function to be called for some event
- type via the :func:`pyramid.events.subscriber` function.
+You can configure a subscriber function to be called for some event
+type via the :func:`pyramid.events.subscriber` function.
- .. code-block:: python
- :linenos:
+.. code-block:: python
+ :linenos:
- from pyramid.events import NewRequest
- from pyramid.events import subscriber
+ from pyramid.events import NewRequest
+ from pyramid.events import subscriber
- @subscriber(NewRequest)
- def mysubscriber(event):
- event.request.foo = 1
+ @subscriber(NewRequest)
+ def mysubscriber(event):
+ event.request.foo = 1
- When the :func:`pyramid.subscriber` decorator is used a
- :term:`scan` must be performed against the package containing the
- decorated function for the decorator to have any effect. See
- :func:`pyramid.subscriber` for more information.
+When the :func:`pyramid.subscriber` decorator is used a
+:term:`scan` must be performed against the package containing the
+decorated function for the decorator to have any effect. See
+:func:`pyramid.subscriber` for more information.
.. note:: You can also configure an event listener via ZCML. See
:ref:`zcml_event_listener`.
diff --git a/docs/narr/handlers.rst b/docs/narr/handlers.rst
new file mode 100644
index 000000000..edeed2de8
--- /dev/null
+++ b/docs/narr/handlers.rst
@@ -0,0 +1,277 @@
+.. _handlers_chapter:
+
+View Handlers
+=============
+
+:app:`Pyramid` provides the special concept of a :term:`view handler`. View
+handlers are view classes that implement a number of methods, each of which
+is a :term:`view callable` as a convenience for :term:`URL dispatch` users.
+
+.. note::
+
+ View handlers are *not* useful when using :term:`traversal`, only when using
+ :term:`url dispatch`. If you are not using url dispatch, you can skip this
+ chapter.
+
+Using a view handler instead of a plain function or class :term:`view
+callable` makes it unnecessary to call
+:meth:`pyramid.config.Configurator.add_route` (and/or
+:meth:`pyramid.config.Configurator.add_view`) "by hand" multiple times,
+making it more pleasant to register a collection of views as a single class
+when using :term:`url dispatch`. The view handler machinery also introduces
+the concept of an ``action``, which is used as a :term:`view predicate` to
+control which method of the handler is called. The method name is the
+default *action name* of a handler view callable.
+
+The concept of a view handler is analogous to a "controller" in Pylons 1.0.
+
+The view handler class is initialized by :app:`Pyramid` in the same manner as
+a "plain" view class. Its ``__init__`` is called with a request object (see
+:ref:`class_as_view`). It implements methods, each of which is a :term:`view
+callable`. When a request enters the system which corresponds with an
+*action* related to one of its view callable methods, this method is called,
+and it is expected to return a response.
+
+Here's an example view handler class:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+
+ from pyramid.view import action
+
+ class Hello(object):
+ def __init__(self, request):
+ self.request = request
+
+ def index(self):
+ return Response('Hello world!')
+
+ @action(renderer="mytemplate.mak")
+ def bye(self):
+ return {}
+
+The :class:`pyramid.view.action` decorator is used to fine-tune the view
+parameters for each potential view callable which is a method of the handler.
+
+.. _using_add_handler:
+
+Handler Registration Using :meth:`~pyramid.config.Configurator.add_handler`
+---------------------------------------------------------------------------
+
+Handlers are added to application configuration via the
+:meth:`pyramid.config.Configurator.add_handler` API. The
+:meth:`~pyramid.config.Configurator.add_handler` method will scan a
+:term:`view handler` class and automatically set up view configurations for
+its methods that represent "auto-exposed" view callable, or those that were
+decorated explicitly with the :class:`~pyramid.view.action` decorator. This
+decorator is used to setup additional view configuration information for
+individual methods of the class, and can be used repeatedly for a single view
+method to register multiple view configurations for it.
+
+.. code-block:: python
+ :linenos:
+
+ from myapp.handlers import Hello
+ config.add_handler('hello', '/hello/{action}', handler=Hello)
+
+This example will result in a route being added for the pattern
+``/hello/{action}``, and each method of the ``Hello`` class will then be
+examined to see if it should be registered as a potential view callable when
+the ``/hello/{action}`` pattern matches. The value of ``{action}`` in the
+route pattern will be used to determine which view should be called, and each
+view in the class will be setup with a view predicate that requires a
+specific ``action`` name. By default, the action name for a method of a
+handler is the method name.
+
+If the URL was ``/hello/index``, the above example pattern would match, and,
+by default, the ``index`` method of the ``Hello`` class would be called.
+
+Alternatively, the action can be declared specifically for a URL to be
+registered for a *specific* ``action`` name:
+
+.. code-block:: python
+ :linenos:
+
+ from myapp.handlers import Hello
+ config.add_handler('hello_index', '/hello/index',
+ handler=Hello, action='index')
+
+This will result one of the methods that are configured for the ``action`` of
+'index' in the ``Hello`` handler class to be called. In this case the name of
+the method is the same as the action name: ``index``. However, this need not
+be the case, as we will see below.
+
+When calling :meth:`~pyramid.config.Configurator.add_handler`, an ``action``
+is required in either the route pattern or as a keyword argument, but
+**cannot appear in both places**. A ``handler`` argument must also be
+supplied, which can be either a :term:`asset specification` or a Python
+reference to the handler class. Additional keyword arguments are passed
+directly through to :meth:`pyramid.config.Configurator.add_route`.
+
+For example:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_handler('hello', '/hello/{action}',
+ handler='mypackage.handlers.MyHandler')
+
+Multiple :meth:`~pyramid.config.Configurator.add_handler` calls can specify
+the same handler, to register specific route names for different
+handler/action combinations. For example:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_handler('hello_index', '/hello/index',
+ handler=Hello, action='index')
+ config.add_handler('bye_index', '/hello/bye',
+ handler=Hello, action='bye')
+
+.. note::
+
+ Handler configuration may also be added to the system via :term:`ZCML` (see
+ :ref:`zcml_handler_configuration`).
+
+View Setup in the Handler Class
+-------------------------------
+
+A handler class can have a single class level attribute called
+``__autoexpose__`` which should be a regular expression or the value
+``None``. It's used to determine which method names will result in additional
+view configurations being registered.
+
+When :meth:`~pyramid.config.Configurator.add_handler` runs, every method in
+the handler class will be searched and a view registered if the method name
+matches the ``__autoexpose__`` regular expression, or if the method was
+decorated with :class:`~pyramid.view.action`.
+
+Every method in the handler class that has a name meeting the
+``__autoexpose__`` regular expression will have a view registered for an
+``action`` name corresponding to the method name. This functionality can be
+disabled by setting the ``__autoexpose__`` attribute to ``None``:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import action
+
+ class Hello(object):
+ __autoexpose__ = None
+
+ def __init__(self, request):
+ self.request = request
+
+ @action()
+ def index(self):
+ return Response('Hello world!')
+
+ @action(renderer="mytemplate.mak")
+ def bye(self):
+ return {}
+
+With auto-expose effectively disabled, no views will be registered for a
+method unless it is specifically decorated with
+:class:`~pyramid.view.action`.
+
+Action Decorators in a Handler
+------------------------------
+
+The :class:`~pyramid.view.action` decorator registers view configuration
+information on the handler method, which is used by
+:meth:`~pyramid.config.Configurator.add_handler` to setup the view
+configuration.
+
+All keyword arguments are recorded, and passed to
+:meth:`~pyramid.config.Configurator.add_view`. Any valid keyword arguments
+for :meth:`~pyramid.config.Configurator.add_view` can thus be used with the
+:class:`~pyramid.view.action` decorator to further restrict when the view
+will be called.
+
+One important difference is that a handler method can respond to an
+``action`` name that is different from the method name by passing in a
+``name`` argument.
+
+Example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import action
+
+ class Hello(object):
+ def __init__(self, request):
+ self.request = request
+
+ @action(name='index', renderer='created.mak', request_method='POST')
+ def create(self):
+ return {}
+
+ @action(renderer="view_all.mak", request_method='GET')
+ def index(self):
+ return {}
+
+This will register two views that require the ``action`` to be ``index``,
+with the additional view predicate requiring a specific request method.
+
+It can be useful to decorate a single method multiple times with
+:class:`~pyramid.view.action`. Each action decorator will register a new view
+for the method. By specifying different names and renderers for each action,
+the same view logic can be exposed and rendered differently on multiple URLs.
+
+Example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import action
+
+ class Hello(object):
+ def __init__(self, request):
+ self.request = request
+
+ @action(name='home', renderer='home.mak')
+ @action(name='about', renderer='about.mak')
+ def show_template(self):
+ # prep some template vars
+ return {}
+
+ # in the config
+ config.add_handler('hello', '/hello/{action}', handler=Hello)
+
+With this configuration, the url ``/hello/home`` will find a view
+configuration that results in calling the ``show_template`` method, then
+rendering the template with ``home.mak``, and the url ``/hello/about`` will
+call the same method and render the ``about.mak`` template.
+
+Handler ``__action_decorator__`` Attribute
+------------------------------------------
+
+If a handler class has an ``__action_decorator__`` attribute, then the
+value of the class attribute will be passed in as the ``decorator``
+argument every time a handler action is registered as a view callable.
+This means that, like anything passed to ``add_view()`` as the
+``decorator`` argument, ``__action_decorator__`` must be a callable
+accepting a single argument. This argument will itself be a callable
+accepting ``(context, request)`` arguments, and
+``__action_decorator__`` must return a replacement callable with the
+same call signature.
+
+Note that, since handler actions are registered as views against the
+handler class and not a handler instance, any ``__action_decorator__``
+attribute must *not* be a regular instance method. Defining an
+``__action_decorator__`` instance method on a handler class will
+result in a :exc:`ConfigurationError`. Instead, ``__action_decorator__``
+can be any other type of callable: a staticmethod, classmethod, function,
+or some sort of callable instance.
+
+.. note::
+
+ In a Pylons 1.0 controller, it was possible to override the ``__call__()``
+ method, which allowed a developer to "wrap" the entire action invocation,
+ with a try/except or any other arbitrary code. In :app:`Pyramid`, this
+ can be emulated with the use of an ``__action_decorator__`` classmethod
+ on your handler class.
+
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index c2a5b8ce7..c7ed18e4c 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -867,11 +867,11 @@ which itself includes an ``LC_MESSAGES`` directory. Each
Each ``.mo`` file represents a :term:`message catalog`, which is used
to provide translations to your application.
-Adding a :term:`translation directory` registers all of its
-constituent :term:`message catalog` files (all of the ``.mo`` files
-found within all ``LC_MESSAGES`` directories within each locale
-directory in the translation directory) within your :app:`Pyramid`
-application to be available to use for translation services.
+Adding a :term:`translation directory` registers all of its constituent
+:term:`message catalog` files within your :app:`Pyramid` application to
+be available to use for translation services. This includes all of the
+``.mo`` files found within all ``LC_MESSAGES`` directories within each
+locale directory in the translation directory.
You can add a translation directory imperatively by using the
:meth:`pyramid.config.Configurator.add_translation_dirs` during
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 62a4727bc..babf66ecd 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -6,13 +6,14 @@
Security
========
-:app:`Pyramid` provides an optional declarative authorization system that
-prevents a :term:`view` from being invoked when the user represented by
-credentials in the :term:`request` does not have an appropriate level of
-access when a particular resource is the :term:`context`. Here's how it
-works at a high level:
+:app:`Pyramid` provides an optional declarative authorization system
+that can prevent a :term:`view` from being invoked based on an
+:term:`authorization policy`. Before a view is invoked, the
+authorization system can use the credentials in the :term:`request`
+along with the :term:`context` resource to determine if access will be
+allowed. Here's how it works at a high level:
-- A :term:`request` is generated when a user visits our application.
+- A :term:`request` is generated when a user visits the application.
- Based on the request, a :term:`context` resource is located through
:term:`resource location`. A context is located differently depending on
@@ -40,6 +41,15 @@ works at a high level:
- If the authorization policy denies access, the view callable is not
invoked; instead the :term:`forbidden view` is invoked.
+Security in :app:`Pyramid`, unlike many systems, cleanly and explicitly
+separates authentication and authorization. Authentication is merely the
+mechanism by which credentials provided in the :term:`request` are
+resolved to one or more :term:`principal` identifiers. These identifiers
+represent the users and groups in effect during the request.
+Authorization then determines access based on the :term:`principal`
+identifiers, the :term:`view callable` being invoked, and the
+:term:`context` resource.
+
Authorization is enabled by modifying your application to include an
:term:`authentication policy` and :term:`authorization policy`.
:app:`Pyramid` comes with a variety of implementations of these
@@ -169,8 +179,8 @@ to invoke the ``blog_entry_add_view`` view. If he does not, the
Setting a Default Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If a permission is not supplied to a view configuration, the
-registered view always be executable by entirely anonymous users: any
+If a permission is not supplied to a view configuration, the registered
+view will always be executable by entirely anonymous users: any
authorization policy in effect is ignored.
In support of making it easier to configure applications which are
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 08c6e355b..1428f3476 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -87,14 +87,15 @@ local` stack, which makes the ``get_current_*`` functions work. It returns a
required by the code under test. :func:`~pyramid.testing.tearDown` pops the
thread local stack.
-Normally when a Configurator is used directly with the ``main`` block of a
-Pyramid application, it defers performing any "real work" until its
+Normally when a Configurator is used directly with the ``main`` block of
+a Pyramid application, it defers performing any "real work" until its
``.commit`` method is called (often implicitly by the
-:meth:`pyramid.config.Configurator.make_wsgi_app` method). The Configurator
-returned by :func:`~pyramid.testing.setUp` is however an *autocommitting*
-Configurator which performs all actions implied by methods called on it
-immediately. This is more convenient for unit-testing purposes than needing
-to call :meth:`pyramid.config.Configurator.commit` in each test after adding
+:meth:`pyramid.config.Configurator.make_wsgi_app` method). The
+Configurator returned by :func:`~pyramid.testing.setUp` is an
+*autocommitting* Configurator, however, which performs all actions
+implied by methods called on it immediately. This is more convenient
+for unit-testing purposes than needing to call
+:meth:`pyramid.config.Configurator.commit` in each test after adding
extra configuration statements.
The use of the :func:`~pyramid.testing.setUp` and
@@ -117,11 +118,10 @@ of using this feature:
testing.tearDown()
The above will make sure that
-:func:`pyramid.threadlocal.get_current_registry` will return the
-:term:`application registry` associated with the ``config`` Configurator
-instance when :func:`pyramid.threadlocal.get_current_registry` is called in a
-test case method attached to ``MyTest``. Each test case method attached to
-``MyTest`` will use an isolated registry.
+:func:`pyramid.threadlocal.get_current_registry` called within a test
+case method of ``MyTest`` will return the :term:`application registry`
+associated with the ``config`` Configurator instance. Each test case
+method attached to ``MyTest`` will use an isolated registry.
The :func:`~pyramid.testing.setUp` and :func:`~pyramid.testing.tearDown`
functions accepts various arguments that influence the environment of the
@@ -148,14 +148,14 @@ other than ``None`` during the course of a single test, you can pass a
testing.tearDown()
If you pass a :term:`request` object into :func:`pyramid.testing.setUp`
-within your test case's ``setUp``, any test method attached to the ``MyTest``
-test case that directly or indirectly calls
-:func:`pyramid.threadlocal.get_current_request` will receive the request you
-passed into the ``begin`` method. Otherwise, during testing,
-:func:`pyramid.threadlocal.get_current_request` will return ``None``. We use
-a "dummy" request implementation supplied by
-:class:`pyramid.testing.DummyRequest` because it's easier to construct than a
-"real" :app:`Pyramid` request object.
+within your test case's ``setUp``, any test method attached to the
+``MyTest`` test case that directly or indirectly calls
+:func:`pyramid.threadlocal.get_current_request` will receive the request
+object. Otherwise, during testing,
+:func:`pyramid.threadlocal.get_current_request` will return ``None``.
+We use a "dummy" request implementation supplied by
+:class:`pyramid.testing.DummyRequest` because it's easier to construct
+than a "real" :app:`Pyramid` request object.
What?
~~~~~
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index 6ab8e9e45..3e0451383 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -135,6 +135,11 @@ method expected to return a response, you can either:
kind of view class which provides more automation when your application
uses :term:`URL dispatch` solely.
+.. note::
+ You can also create :term:`view handler` classes that define
+ multiple view callables similar to "controllers" in Pylons 1.0. See
+ the :ref:`handlers_chapter` chapter for details.
+
.. index::
single: view calling convention