From 10fd8fe6bc26a7241542353032540cd4415ee9cc Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 24 Dec 2010 17:09:32 -0500 Subject: - Added "Advanced Configuration" narrative chapter which documents how to deal with configuration conflicts, two-phase configuration, ``include`` and ``commit``. --- docs/narr/advconfig.rst | 373 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 docs/narr/advconfig.rst (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst new file mode 100644 index 000000000..a4692e4c6 --- /dev/null +++ b/docs/narr/advconfig.rst @@ -0,0 +1,373 @@ +.. index:: + pair: advanced; configuration + +.. _advconfig_narr: + +Advanced Configuration +====================== + +To support application extensibility, the :app:`Pyramid` +:term:`Configurator`, by default, detects configuration conflicts and allows +you to include configuration imperatively from other packages or modules. It +also, by default, performs configuration in two separate phases. This allows +you to ignore relative configuration statement ordering in some +circumstances. + +.. index:: + single: imperative configuration + +.. _conflict_detection: + +Conflict Detection +------------------ + +Here's a familiar example of one of the simplest :app:`Pyramid` applications, +configured imperatively: + +.. code-block:: python + :linenos: + + from paste.httpserver import serve + from pyramid.config import Configurator + from pyramid.response import Response + + def hello_world(request): + return Response('Hello world!') + + if __name__ == '__main__': + config = Configurator() + config.add_view(hello_world) + app = config.make_wsgi_app() + serve(app, host='0.0.0.0') + +When you start this application, all will be OK. However, what happens if we +try to add another view to the configuration with the same set of +:term:`predicate` arguments as one we've already added? + +.. code-block:: python + :linenos: + + from paste.httpserver import serve + from pyramid.config import Configurator + from pyramid.response import Response + + def hello_world(request): + return Response('Hello world!') + + def goodbye_world(request): + return Response('Goodbye world!') + + if __name__ == '__main__': + config = Configurator() + + config.add_view(hello_world, name='hello') + + # conflicting view configuration + config.add_view(goodbye_world, name='hello') + + app = config.make_wsgi_app() + serve(app, host='0.0.0.0') + +The application now has two conflicting view configuration statements. When +we try to start it again, it won't start. Instead, we'll receive a traceback +that ends something like this: + +.. code-block:: guess + :linenos: + + Traceback (most recent call last): + File "app.py", line 12, in + app = config.make_wsgi_app() + File "pyramid/config.py", line 839, in make_wsgi_app + self.commit() + File "pyramid/pyramid/config.py", line 473, in commit + self._ctx.execute_actions() + File "zope/configuration/config.py", line 600, in execute_actions + for action in resolveConflicts(self.actions): + File "zope/configuration/config.py", line 1507, in resolveConflicts + raise ConfigurationConflictError(conflicts) + zope.configuration.config.ConfigurationConflictError: + Conflicting configuration actions + For: ('view', None, '', None, , + None, None, None, None, None, False, None, None, None) + ('app.py', 14, '', 'config.add_view(hello_world)') + ('app.py', 17, '', 'config.add_view(hello_world)') + +This traceback is trying to tell us: + +- We've got conflicting information for a set of view configuration + statements (The ``For:`` line). + +- There are two statements which conflict, shown beneath the ``For:`` line: + ``config.add_view(hello_world. 'hello')`` on line 14 of ``app.py``, and + ``config.add_view(goodbye_world, 'hello')`` on line 17 of ``app.py``. + +These two configuration statements are in conflict because we've tried to +tell the system that the set of :term:`predicate` values for both view +configurations are exactly the same. Both the ``hello_world`` and +``goodbye_world`` views are configured to respond under the same set of +circumstances. This circumstance: the :term:`view name` (represented by the +``name=`` predicate) is ``hello``. + +This presents an ambiguity that :app:`Pyramid` cannot resolve. Rather than +allowing the circumstance to go unreported, by default Pyramid raises a +:exc:`ConfigurationConflictError` error and prevents the application from +running. + +Conflict detection happens for any kind of configuration: imperative +configuration, :term:`ZCML` configuration, or configuration that results from +the execution of a :term:`scan`. + +Manually Resolving Conflicts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are a number of ways to manually resolve conflicts: the "right" way, by +strategically using :meth:`pyramid.config.Configurator.commit`, or by using +an "autocommitting" configurator. + +The Right Thing ++++++++++++++++ + +The most correct way to resolve conflicts is to "do the needful": change your +configuration code to not have conflicting configuration statements. The +details of how this is done depends entirely on the configuration statements +made by your application. Use the detail provided in the +:exc:`ConfigurationConflictError` to track down the offending conflicts and +modify your configuration code accordingly. + +If you're getting a conflict while trying to extend an existing application, +and that application has a function which performs configuration like this +one: + +.. code-block:: python + :linenos: + + def add_routes(config): + config.add_route(...) + +Don't call this function directly with ``config`` as an argument. Instead, +use :meth:`pyramid.config.Configuration.include`: + +.. code-block:: python + :linenos: + + config.include(add_routes) + +Using :meth:`~pyramid.config.Configuration.include` instead of calling the +function directly provides a modicum of automated conflict resolution, with +the configuration statements you define in the calling code overriding those +of the included function. See also :ref:`automatic_conflict_resolution` and +:ref:`including_configuration`. + +Using ``config.commit()`` ++++++++++++++++++++++++++ + +You can manually commit a configuration by using the +:meth:`pyramid.config.Configurator.commit` method between configuration +calls. For example, we can make the application we examined previously which +generated a conflict exception + +.. code-block:: python + :linenos: + + from paste.httpserver import serve + from pyramid.config import Configurator + from pyramid.response import Response + + def hello_world(request): + return Response('Hello world!') + + def goodbye_world(request): + return Response('Goodbye world!') + + if __name__ == '__main__': + config = Configurator() + + config.add_view(hello_world, name='hello') + + # conflicting view configuration + config.add_view(goodbye_world, name='hello') + + app = config.make_wsgi_app() + serve(app, host='0.0.0.0') + +We can prevent the two ``add_view`` calls from conflicting by issuing a call +to :meth:`~pyramid.config.Configurator.commit` between them: + +.. code-block:: python + :linenos: + + from paste.httpserver import serve + from pyramid.config import Configurator + from pyramid.response import Response + + def hello_world(request): + return Response('Hello world!') + + def goodbye_world(request): + return Response('Goodbye world!') + + if __name__ == '__main__': + config = Configurator() + + config.add_view(hello_world, name='hello') + + config.commit() # commit any pending configuration actions + + # no-longer-conflicting view configuration + config.add_view(goodbye_world, name='hello') + + app = config.make_wsgi_app() + serve(app, host='0.0.0.0') + +In the above example we've issued a call to +:meth:`~pyramid.config.Configurator.commit` between the two ``add_view`` +calls. :meth:`~pyramid.config.Configurator.commit` will cause any pending +configuration statements. + +Calling :meth:`~pyramid.config.Configurator.commit` is safe at any time. It +executes all pending configuration actions and leaves the configuration +action list "clean". + +.. _autocommitting_configurator: + +Using An Autocommitting Configurator +++++++++++++++++++++++++++++++++++++ + +You can also use a heavy hammer to circumvent conflict detection by using a +configurator constructor parameter: ``autocommit=True``. For example: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + if __name__ == '__main__': + config = Configurator(autocommit=True) + +When the ``autocommit`` parameter passed to the Configurator is ``True``, +conflict detection (and :ref:`twophase_config`) is disabled. +:meth:`pyramid.config.Configurator.commit` has no effect when ``autocommit`` +is ``True`` either. + +If you use a Configurator in code that performs unit testing, it's usually a +good idea to use an autocommitting Configurator, because you are usually +unconcerned about conflict detection or two-phase configuration in test code. + +.. _automatic_conflict_resolution: + +Automatic Conflict Resolution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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 + +Automatic conflict resolution supports this goal: if a user wants to reuse a +Pyramid application, and they want to customize the configuration of this +application without hacking its code "from outside", they can "include" the +package and override only some of its configuration statements within the +code that does the include. No conflicts will be generated by configuration +statements within the code which does the including, even if configuration +statements in the included code would conflict if it was moved "up" to the +calling code. + +Methods Which Provide Conflict Detection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These are the methods of the configurator which provide conflict detection: + +:meth:`~pyramid.config.Configurator.add_view`, +:meth:`~pyramid.config.Configurator.add_route`, +:meth:`~pyramid.config.Configurator.add_renderer`, +:meth:`~pyramid.config.Configurator.set_request_factory`, +:meth:`~pyramid.config.Configurator.set_renderer_globals_factory` +:meth:`~pyramid.config.Configurator.set_locale_negotiator` and +:meth:`~pyramid.config.Configurator.set_default_permission`. + +Some other methods of the configurator also indirectly provide conflict +detection, because they're implemented in terms of conflict-aware methods: + +- :meth:`~pyramid.config.Configurator.add_handler`, a frontend for + ``add_route`` and ``add_view``. + +- :meth:`~pyramid.config.Configurator.add_route` does a second type of + conflict detection when a ``view`` parameter is passed (it calls + ``add_view``). + +- :meth:`~pyramid.config.Configurator.static_view`, a frontend for + ``add_route`` and ``add_view``. + +.. _including_configuration: + +Including Configuration from External Sources +--------------------------------------------- + +Some application programmers will factor their configuration code in such a +way that it is easy to reuse and override configuration statements. For +example, such a developer might factor out a function used to add routes to +his application: + +.. code-block:: python + :linenos: + + def add_routes(config): + config.add_route(...) + +Rather than calling this function directly with ``config`` as an argument. +Instead, use :meth:`pyramid.config.Configuration.include`: + +.. code-block:: python + :linenos: + + config.include(add_routes) + +Using ``include`` rather than calling the function directly will allow +:ref:`automatic_conflict_resolution` to work. + +.. _twophase_config: + +Two-Phase Configuration +----------------------- + +When a non-autocommitting :term:`Configurator` is used to do configuration +(the default), configuration execution happens in two phases. In the first +phase, "eager" configuration actions (actions that must happen before all +others, such as registering a renderer) are executed, and *discriminators* +are computed for each of the actions that depend on the result of the eager +actions. In the second phase, the discriminators of all actions are compared +to do conflict detection. + +Due to this, for configuration methods that have no internal ordering +constraints, execution order of configuration method calls is not important. +For example, the relative ordering of +:meth:`pyramid.config.Configurator.add_view` and +:meth:`pyramid.config.Configurator.add_renderer` is unimportant when a +non-autocommitting configurator is used. This code snippet: + +.. code-block:: python + :linenos: + + config.add_view('some.view', renderer='path_to_custom/renderer.rn') + config.add_renderer('.rn', SomeCustomRendererFactory) + +Has the same result as: + +.. code-block:: python + :linenos: + + config.add_renderer('.rn', SomeCustomRendererFactory) + config.add_view('some.view', renderer='path_to_custom/renderer.rn') + +Even though the view statement depends on the registration of a custom +renderer, due to two-phase configuration, the order in which the +configuration statements are issued is not important. + +The same is untrue when you use an *autocommitting* configurator (see +:ref:`autocommitting_configurator`). When an autocommitting configurator is +used, two-phase configuration is disabled, and configuration statements must +be ordered in dependency order. + + -- cgit v1.2.3 From ef492de9cc24c573faaf12d654267480202fe645 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 24 Dec 2010 17:20:00 -0500 Subject: fix --- docs/narr/advconfig.rst | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index a4692e4c6..2ed0a96ab 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -164,8 +164,9 @@ Using ``config.commit()`` You can manually commit a configuration by using the :meth:`pyramid.config.Configurator.commit` method between configuration -calls. For example, we can make the application we examined previously which -generated a conflict exception +calls. For example, we prevent conflicts from occurring in the application +we examined previously as the result of adding a ``commit``. Here's the +application that generates conflicts: .. code-block:: python :linenos: @@ -229,6 +230,10 @@ Calling :meth:`~pyramid.config.Configurator.commit` is safe at any time. It executes all pending configuration actions and leaves the configuration action list "clean". +Note that :meth:`~pyramid.config.Configurator.commit` has no effect when +you're using an *autocommitting* configurator (see +:ref:`autocommitting_configurator`). + .. _autocommitting_configurator: Using An Autocommitting Configurator @@ -246,9 +251,12 @@ configurator constructor parameter: ``autocommit=True``. For example: config = Configurator(autocommit=True) When the ``autocommit`` parameter passed to the Configurator is ``True``, -conflict detection (and :ref:`twophase_config`) is disabled. +conflict detection (and :ref:`twophase_config`) is disabled. Configuration +statements will be executed immediately, and succeeding statements will +override preceding ones. + :meth:`pyramid.config.Configurator.commit` has no effect when ``autocommit`` -is ``True`` either. +is ``True``. If you use a Configurator in code that performs unit testing, it's usually a good idea to use an autocommitting Configurator, because you are usually @@ -267,12 +275,12 @@ the "include" method. See also Automatic conflict resolution supports this goal: if a user wants to reuse a Pyramid application, and they want to customize the configuration of this -application without hacking its code "from outside", they can "include" the -package and override only some of its configuration statements within the -code that does the include. No conflicts will be generated by configuration -statements within the code which does the including, even if configuration -statements in the included code would conflict if it was moved "up" to the -calling code. +application without hacking its code "from outside", they can "include" a +configuration function from the package and override only some of its +configuration statements within the code that does the include. No conflicts +will be generated by configuration statements within the code which does the +including, even if configuration statements in the included code would +conflict if it was moved "up" to the calling code. Methods Which Provide Conflict Detection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From c1b032a5a31a23d28767d2fce66d6a0f5b835791 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 24 Dec 2010 17:31:58 -0500 Subject: internal ordering --- docs/narr/advconfig.rst | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 2ed0a96ab..68e3796fe 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -378,4 +378,10 @@ The same is untrue when you use an *autocommitting* configurator (see used, two-phase configuration is disabled, and configuration statements must be ordered in dependency order. +Some configuration methods, such as +:meth:`pyramid.config.Configurator.add_route` and +:meth:`pyramid.config.Configurator.add_handler` have internal ordering +constraints: they routes they imply require relative ordering. Such ordering +constraints are not absolved by two-phase configuration. Routes are still +added in configuration execution order. -- cgit v1.2.3 From ec0834c7554010f064e836588211f8c671b950be Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 24 Dec 2010 17:33:42 -0500 Subject: internal ordering --- docs/narr/advconfig.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 68e3796fe..e096ef863 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -371,7 +371,9 @@ Has the same result as: Even though the view statement depends on the registration of a custom renderer, due to two-phase configuration, the order in which the -configuration statements are issued is not important. +configuration statements are issued is not important. ``add_view`` will be +able to find the ``.rn`` renderer even if ``add_renderer`` is called after +``add_view``. The same is untrue when you use an *autocommitting* configurator (see :ref:`autocommitting_configurator`). When an autocommitting configurator is -- cgit v1.2.3 From d1432f4f3c48106252b292f19442bf591c554fa5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 27 Dec 2010 00:57:34 -0500 Subject: - Reconcile "extending an existing application" chapter with existence of "advanced configuration" chapter. --- docs/narr/advconfig.rst | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index e096ef863..f8b3ee191 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -118,6 +118,9 @@ Conflict detection happens for any kind of configuration: imperative configuration, :term:`ZCML` configuration, or configuration that results from the execution of a :term:`scan`. +.. note:: If you use, ZCML, its conflict detection algorithm is described in + :ref:`zcml_conflict_detection`. + Manually Resolving Conflicts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -335,6 +338,9 @@ Instead, use :meth:`pyramid.config.Configuration.include`: Using ``include`` rather than calling the function directly will allow :ref:`automatic_conflict_resolution` to work. +.. note: See :ref:`the_include_tag` for a declarative alternative to + :meth:`pyramid.config.Configurator.include`. + .. _twophase_config: Two-Phase Configuration -- cgit v1.2.3 From 314283a5bec3159d5a0c7e4d7028a0feecd47fa0 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Jan 2011 16:39:54 -0500 Subject: document 'includeme' --- docs/narr/advconfig.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index f8b3ee191..c983bbb57 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -338,6 +338,23 @@ Instead, use :meth:`pyramid.config.Configuration.include`: Using ``include`` rather than calling the function directly will allow :ref:`automatic_conflict_resolution` to work. +:meth:`pyramid.config.Configuration.include` can also accept a :term:`module` +as an argument: + +.. code-block:: python + :linenos: + + import myapp + + config.include(myapp) + +For this to work properly, the ``myapp`` module must contain a callable with +the special name ``includeme``, which should perform configuration (like the +``add_routes`` callable we showed above as an example). + +:meth:`pyramid.config.Configuration.include` can also accept a :term:`dotted +Python name` to a function or a module. + .. note: See :ref:`the_include_tag` for a declarative alternative to :meth:`pyramid.config.Configurator.include`. -- cgit v1.2.3 From 2fa5764cb1fd001550ae7c985333718667b86b1c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 16 Jan 2011 17:41:10 -0500 Subject: - The ``pylons_minimal``, ``pylons_basic`` and ``pylons_sqla`` paster templates were removed. Use ``pyramid_sqla`` (available from PyPI) as a generic replacement for Pylons-esque development. - All references to ``add_handler`` and the ``handler`` ZCML directive have been removed from the docs, and stubs which point to ``pylons_handlers`` package have replaced them. --- docs/narr/advconfig.rst | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index c983bbb57..eb9b70b12 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -301,9 +301,6 @@ These are the methods of the configurator which provide conflict detection: Some other methods of the configurator also indirectly provide conflict detection, because they're implemented in terms of conflict-aware methods: -- :meth:`~pyramid.config.Configurator.add_handler`, a frontend for - ``add_route`` and ``add_view``. - - :meth:`~pyramid.config.Configurator.add_route` does a second type of conflict detection when a ``view`` parameter is passed (it calls ``add_view``). @@ -404,8 +401,7 @@ used, two-phase configuration is disabled, and configuration statements must be ordered in dependency order. Some configuration methods, such as -:meth:`pyramid.config.Configurator.add_route` and -:meth:`pyramid.config.Configurator.add_handler` have internal ordering +:meth:`pyramid.config.Configurator.add_route` have internal ordering constraints: they routes they imply require relative ordering. Such ordering constraints are not absolved by two-phase configuration. Routes are still added in configuration execution order. -- cgit v1.2.3 From c9c3c487bcaedeca97bb6463a00188b0dc01203a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 18 Jan 2011 12:25:56 -0500 Subject: - Most references to ZCML in narrative chapters have been removed or redirected to ``pyramid_zcml`` locations. --- docs/narr/advconfig.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index eb9b70b12..8951166f5 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -115,11 +115,8 @@ allowing the circumstance to go unreported, by default Pyramid raises a running. Conflict detection happens for any kind of configuration: imperative -configuration, :term:`ZCML` configuration, or configuration that results from -the execution of a :term:`scan`. - -.. note:: If you use, ZCML, its conflict detection algorithm is described in - :ref:`zcml_conflict_detection`. +configuration or configuration that results from the execution of a +:term:`scan`. Manually Resolving Conflicts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From d5d0b34aeb1af8e3df031215df3f113c392833a6 Mon Sep 17 00:00:00 2001 From: Casey Duncan Date: Tue, 18 Jan 2011 18:24:21 -0700 Subject: remove empty See Also --- docs/narr/advconfig.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index eb9b70b12..1e2e7a0e9 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -274,7 +274,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 -- cgit v1.2.3 From 6430c7b3aa3f2f1e47d3a647a70c0a953fcbb23c Mon Sep 17 00:00:00 2001 From: Casey Duncan Date: Tue, 18 Jan 2011 18:28:15 -0700 Subject: they => the --- docs/narr/advconfig.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 1e2e7a0e9..4b10e6194 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -402,7 +402,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. -- cgit v1.2.3 From 14e91bfd4af61251853b73aad33ff47c237339aa Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 19 Jan 2011 22:27:06 -0500 Subject: - Added "Adding Methods to the Configurator via ``add_directive``" section to Advanced Configuration narrative chapter. --- docs/narr/advconfig.rst | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 30f76e456..1cdf1e945 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -403,3 +403,70 @@ 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. +Adding Methods to the Configurator via ``add_directive`` +-------------------------------------------------------- + +Framework extension writers can add arbitrary methods to a +:term:`Configurator` by using the +:meth:`pyramid.config.Configurator.add_directive` method of the configurator. +This makes it possible to extend a Pyramid configurator in arbitrary ways, +and allows it to perform application-specific tasks more succinctly. + +The :meth:`~pyramid.config.Configurator.add_directive` method accepts two +positional arguments: a method name and a callable object. The callable +object is usually a function that takes the configurator instance as its +first argument and accepts other arbitrary positional and keyword arguments. +For example: + +.. code-block:: python + :linenos: + + from pyramid.events import NewRequest + from pyramid.config import Configurator + + def add_newrequest_subscriber(config, subscriber): + config.add_subscriber(subscriber, NewRequest). + + if __name__ == '__main__': + config = Configurator() + config.add_directive('add_newrequest_subscriber', + add_newrequest_subscriber) + +Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can +then call the method by its given name as if it were a built-in method of the +Configurator: + +.. code-block:: python + :linenos: + + def mysubscriber(event): + print event.request + + config.add_newrequest_subscriber(mysubscriber) + +A call to :meth:`~pyramid.config.Configurator.add_directive` is often +"hidden" within an ``includeme`` function within a "frameworky" package meant +to be included as per :ref:`including_configuration` via +:meth:`~pyramid.config.Configurator.include`. For example, if you put this +code in a package named ``pyramid_subscriberhelpers``: + +.. code-block:: python + :linenos: + + def includeme(config) + config.add_directive('add_newrequest_subscriber', + add_newrequest_subscriber) + +The user of the add-on package ``pyramid_subscriberhelpers`` would then be +able to install it and subsequently do: + +.. code-block:: python + :linenos: + + def mysubscriber(event): + print event.request + + from pyramid.config import Configurator + config = Configurator() + config.include('pyramid_subscriberhelpers') + config.add_newrequest_subscriber(mysubscriber) -- cgit v1.2.3 From c88d441533c46c80d3e08572013973446308ebd5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 21 Jan 2011 04:04:45 -0500 Subject: - Added "What's New in Pyramid 1.0" chapter to HTML rendering of documentation. --- docs/narr/advconfig.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 1cdf1e945..20316dc77 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -403,6 +403,8 @@ 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. +.. _add_directive: + Adding Methods to the Configurator via ``add_directive`` -------------------------------------------------------- -- cgit v1.2.3 From 70acd25f40f32fc6cbb3b5d38a695b8982b52a31 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 27 Jan 2011 23:06:55 -0500 Subject: module name contractions --- docs/narr/advconfig.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'docs/narr/advconfig.rst') diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 20316dc77..099bce35f 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -163,7 +163,7 @@ Using ``config.commit()`` +++++++++++++++++++++++++ You can manually commit a configuration by using the -:meth:`pyramid.config.Configurator.commit` method between configuration +:meth:`~pyramid.config.Configurator.commit` method between configuration calls. For example, we prevent conflicts from occurring in the application we examined previously as the result of adding a ``commit``. Here's the application that generates conflicts: @@ -255,7 +255,7 @@ conflict detection (and :ref:`twophase_config`) is disabled. Configuration statements will be executed immediately, and succeeding statements will override preceding ones. -:meth:`pyramid.config.Configurator.commit` has no effect when ``autocommit`` +:meth:`~pyramid.config.Configurator.commit` has no effect when ``autocommit`` is ``True``. If you use a Configurator in code that performs unit testing, it's usually a @@ -267,7 +267,7 @@ unconcerned about conflict detection or two-phase configuration in test code. Automatic Conflict Resolution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If your code uses the :meth:`pyramid.config.Configurator.include` method to +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 @@ -332,7 +332,7 @@ Instead, use :meth:`pyramid.config.Configuration.include`: Using ``include`` rather than calling the function directly will allow :ref:`automatic_conflict_resolution` to work. -:meth:`pyramid.config.Configuration.include` can also accept a :term:`module` +:meth:`~pyramid.config.Configuration.include` can also accept a :term:`module` as an argument: .. code-block:: python @@ -346,11 +346,11 @@ For this to work properly, the ``myapp`` module must contain a callable with the special name ``includeme``, which should perform configuration (like the ``add_routes`` callable we showed above as an example). -:meth:`pyramid.config.Configuration.include` can also accept a :term:`dotted +:meth:`~pyramid.config.Configuration.include` can also accept a :term:`dotted Python name` to a function or a module. .. note: See :ref:`the_include_tag` for a declarative alternative to - :meth:`pyramid.config.Configurator.include`. + the :meth:`~pyramid.config.Configurator.include` method. .. _twophase_config: @@ -368,8 +368,8 @@ to do conflict detection. Due to this, for configuration methods that have no internal ordering constraints, execution order of configuration method calls is not important. For example, the relative ordering of -:meth:`pyramid.config.Configurator.add_view` and -:meth:`pyramid.config.Configurator.add_renderer` is unimportant when a +:meth:`~pyramid.config.Configurator.add_view` and +:meth:`~pyramid.config.Configurator.add_renderer` is unimportant when a non-autocommitting configurator is used. This code snippet: .. code-block:: python @@ -398,7 +398,7 @@ used, two-phase configuration is disabled, and configuration statements must be ordered in dependency order. Some configuration methods, such as -:meth:`pyramid.config.Configurator.add_route` have internal ordering +:meth:`~pyramid.config.Configurator.add_route` have internal 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. -- cgit v1.2.3