diff options
| -rw-r--r-- | docs/index.rst | 1 | ||||
| -rw-r--r-- | docs/latexindex.rst | 1 | ||||
| -rw-r--r-- | docs/narr/advconfig.rst | 4 | ||||
| -rw-r--r-- | docs/narr/environment.rst | 17 | ||||
| -rw-r--r-- | docs/narr/events.rst | 62 | ||||
| -rw-r--r-- | docs/narr/extending.rst | 8 | ||||
| -rw-r--r-- | docs/narr/handlers.rst | 277 | ||||
| -rw-r--r-- | docs/narr/hooks.rst | 13 | ||||
| -rw-r--r-- | docs/narr/i18n.rst | 10 | ||||
| -rw-r--r-- | docs/narr/router.rst | 2 | ||||
| -rw-r--r-- | docs/narr/security.rst | 26 | ||||
| -rw-r--r-- | docs/narr/testing.rst | 40 | ||||
| -rw-r--r-- | docs/narr/views.rst | 5 | ||||
| -rw-r--r-- | docs/narr/zca.rst | 2 |
14 files changed, 387 insertions, 81 deletions
diff --git a/docs/index.rst b/docs/index.rst index 030b4dc1c..a5fc6f13a 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 2426ec4b0..9716e26d0 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/advconfig.rst b/docs/narr/advconfig.rst index 8951166f5..30f76e456 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -271,7 +271,7 @@ If your code uses the :meth:`pyramid.config.Configurator.include` method to include external configuration, some conflicts are automatically resolved. Configuration statements that are made as the result of an "include" will be overridden by configuration statements that happen within the caller of -the "include" method. See also +the "include" method. Automatic conflict resolution supports this goal: if a user wants to reuse a Pyramid application, and they want to customize the configuration of this @@ -399,7 +399,7 @@ be ordered in dependency order. Some configuration methods, such as :meth:`pyramid.config.Configurator.add_route` have internal ordering -constraints: they routes they imply require relative ordering. Such ordering +constraints: the routes they imply require relative ordering. Such ordering constraints are not absolved by two-phase configuration. Routes are still added in configuration execution order. 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 6fc3d1424..224eeca16 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. Either of the above registration examples implies that every time the :app:`Pyramid` framework emits an event object that supplies an diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst index eb7f0b24e..eb905acd4 100644 --- a/docs/narr/extending.rst +++ b/docs/narr/extending.rst @@ -196,7 +196,7 @@ like this: :ref:`creating_a_project` for more information. - In the new package, create Python files containing views and other - overridden elements, such as templates and static resources as necessary. + overridden elements, such as templates and static assets as necessary. - Install the new package into the same Python environment as the original application (e.g. ``python setup.py develop`` or ``python setup.py @@ -278,7 +278,7 @@ into the override package's file and changing them as necessary. Then disinclude any ``add_route`` statements from the original application. .. index:: - pair: overriding; resources + pair: overriding; assets .. _overriding_resources: @@ -286,10 +286,10 @@ Overriding Assets ~~~~~~~~~~~~~~~~~ Assets are files on the filesystem that are accessible within a Python -*package*. An entire chapter is devoted to resources: :ref:`assets_chapter`. +*package*. An entire chapter is devoted to assets: :ref:`assets_chapter`. Within this chapter is a section named :ref:`overriding_assets_section`. This section of that chapter describes in detail how to override package -resources with other resources by using the +assets with other assets by using the :meth:`pyramid.config.Configurator.override_asset` method. Add such ``override_asset`` calls to your override package's ``__init__.py`` to perform overrides. 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/hooks.rst b/docs/narr/hooks.rst index f75e0bcf5..6b1522846 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -354,10 +354,11 @@ parameter: ``request``. For example: transaction.commit() request.add_finished_callback(commit_callback) -Finished callbacks are called in the order they're added ( first- to -most-recently- added). Finished callbacks (unlike a :term:`response -callback`) are *always* called, even if an exception happens in application -code that prevents a response from being generated. +Finished callbacks are called in the order they're added +(first-to-most-recently-added). Finished callbacks (unlike a +:term:`response callback`) are *always* called, even if an exception +happens in application code that prevents a response from being +generated. The set of finished callbacks associated with a request are called *very late* in the processing of that request; they are essentially the very last @@ -535,8 +536,8 @@ Using a View Mapper ------------------- The default calling conventions for view callables are documented in the -:ref:`views_chapter`. You can change the way users define view callbles by -employing a :term:`view mapper`. +:ref:`views_chapter` chapter. You can change the way users define view +callbles by employing a :term:`view mapper`. A view mapper is an object that accepts a set of keyword arguments and which returns a callable. The returned callable is called with the :term:`view diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst index e1b6acc7b..83973a17e 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/router.rst b/docs/narr/router.rst index f9e98373c..782098bac 100644 --- a/docs/narr/router.rst +++ b/docs/narr/router.rst @@ -44,7 +44,7 @@ processing? #. If any route matches, the request is mutated; a ``matchdict`` and ``matched_route`` attributes are added to the request object; the - former contains a dictionary representign the matched dynamic + former contains a dictionary representing the matched dynamic elements of the request's ``PATH_INFO`` value, the latter contains the :class:`pyramid.interfaces.IRoute` object representing the route which matched. The root object associated with the route diff --git a/docs/narr/security.rst b/docs/narr/security.rst index ebaeb1526..e395b15f1 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 @@ -163,8 +173,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 b9c62ea53..0968ad229 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 diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst index 394d02625..78a7b0b75 100644 --- a/docs/narr/zca.rst +++ b/docs/narr/zca.rst @@ -57,7 +57,7 @@ Using the ZCA Global API in a :app:`Pyramid` Application ----------------------------------------------------------- :term:`Zope` uses a single ZCA registry -- the "global" ZCA registry --- for all Zope applications run in the same Python process, +-- for all Zope applications that run in the same Python process, effectively making it impossible to run more than one Zope application in a single process. |
