From f6c1495fa1712cca94de8034afafc73a6790f591 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 23 Nov 2009 09:59:24 +0000 Subject: Documentation improvements. --- docs/narr/configuration.rst | 253 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 249 insertions(+), 4 deletions(-) (limited to 'docs/narr/configuration.rst') diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst index 6be8daa73..09e412c30 100644 --- a/docs/narr/configuration.rst +++ b/docs/narr/configuration.rst @@ -67,6 +67,8 @@ There are a number of different mechanisms you may use to configure and *declarative* configuration. We'll examine both modes in the sections which follow. +.. _helloworld_imperative: + Hello World, Configured Imperatively ------------------------------------ @@ -174,6 +176,8 @@ requesting user agent. The view callable defined by the script does nothing but return a response with the body ``Hello world!``. +.. _helloworld_imperative_appconfig: + Application Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -318,10 +322,10 @@ an XML dialect. Declarative configuration mode is the configuration mode in which developers cede the most amount of control to the framework itself. Because application developers cede a more control to the framework, -it is also the hardest mode of configuration to understand. However, -using declarative configuration has a number of benefits, the primary -benefit being that applications configured declaratively can be -*overridden* and *extended* by third parties without requiring the +it is also harder to understand than purely imperative configuration. +However, using declarative configuration has a number of benefits, the +primary benefit being that applications configured declaratively can +be *overridden* and *extended* by third parties without requiring the third party to change application code. .. note:: @@ -367,3 +371,244 @@ previously created ``helloworld.py``: +This pair of files forms an application functionally equivalent to the +application we created earlier. Let's examine the differences between +the code described in :ref:`helloworld_imperative`" and the code +above. + +In :ref:`helloworld_imperative_appconfig`, we had the following lines +within the ``if __name__ == '__main__'`` section of ``helloworld.py``: + +.. code-block:: python + :linenos: + + if __name__ == '__main__': + config = Configurator() + config.view(hello_world) + app = config.make_wsgi_app() + simple_server.make_server('', 8080, app).serve_forever() + +In our "declarative" code, we've added a ``zcml_file`` argument to the +``Configurator`` constructor's argument list with the value +``configure.zcml``, and we've removed the line which reads +``config.view(hello_world)``, so that it now reads as: + +.. code-block:: python + :linenos: + + if __name__ == '__main__': + config = Configurator(zcml_file='configure.zcml') + app = config.make_wsgi_app() + simple_server.make_server('', 8080, app).serve_forever() + +Everything else is much the same. + +The ``zcml_file`` argument to the ``Configurator`` constructor tells +the configurator to load configuration declarations from the +``configure.zcml`` file which sits next to ``helloworld.py``. Let's +take a look at the ``configure.zcml`` file now: + +.. code-block:: xml + :linenos: + + + + + + + + + +The ```` Tag +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``configure.zcml`` ZCML file contains this bit of XML: + +.. code-block:: xml + :linenos: + + + ... body ... + + +Because :term:`ZCML` is XML, and because XML requires a single root +tag for each document, every ZCML file used by :mod:`repoze.bfg` must +contain a ```` container tag, which acts as the root XML +tag. Usually, the start tag of the ```` container tag has +a default namespace associated with it. In the file above, the +``xmlns="http:/namepaces.repoze.org/bfg"`` attribute of the +``configure`` start tag names the default XML namespace, which is +``http://namespaces.repoze.org/bfg``. See +:ref:`word_on_xml_namespaces` for more information about XML +namespaces. + +The ```` Tag +~~~~~~~~~~~~~~~~~~~~~ + +The ``configure.zcml`` ZCML file contains this bit of XML within the +root tag: + +.. code-block:: xml + :linenos: + + + +This singleton (self-closing) tag instructs ZCML to load a ZCML file +from the Python package with the :term:`dotted Python name` +``repoze.bfg.includes``, as specified by its ``package`` attribute. +This particular ```` declaration is required because it +actually allows subseqent declaration tags (such as ````, which +we'll see shortly) to be recognized. The ```` tag +effectively just includes another ZCML file; this causes its +declarations to be executed. In this case, we want to load the +declarations from the file named ``configure.zcml`` within the +``repoze.bfg.includes`` Python package. We know we want to load the +``configure.zcml`` from this package because ``configure.zcml`` is the +default value for another attribute of the ```` tag named +``file``. We could have spelled the include tag more verbosely, but +equivalently as: + +.. code-block:: xml + :linenos: + + + +The ```` tag that includes the ZCML statements implied by the +``configure.zcml`` file from the Python package named +``repoze.bfg.includes`` is basically required to come before any other +named declaration in an application's ``configure.zcml``. If it is +not included, subsequent declaration tags will fail to be recognized, +and the configuration system will generate a traceback. However, the +```` tag needs to exist only +in a "top-level" ZCML file, it needn't also exist in ZCML files +*included by* a top-level ZCML file. + +The ```` Tag +~~~~~~~~~~~~~~~~~~ + +The ``configure.zcml`` ZCML file contains this bit of XML after the +```` tag, but within the root tag: + +.. code-block:: xml + :linenos: + + + +This ```` declaration tag directs :mod:`repoze.bfg` to create a +:term:`view configuration`. This ```` tag has an attribute +(also named ``view``), which points at a :term:`dotted Python name`, +referencing the ``hello_world`` function defined within the +``helloworld`` package. This tag is functionally equivalent to a +line we saw previously in our imperatively-configured application: + +.. code-block:: python + :linenos: + + config.view(hello_world) + +The ```` declaration tag effectively invokes the ``view`` method +of the ``Configurator`` object on your behalf. Various attributes can +be specified on the ```` tag which influence the :term:`view +configuration` it creates. + +The ```` tag is an example of a :mod:`repoze.bfg` declaration +tag. Other such tags include ````, ````, ````, +````, and others. All of these tags are effectively +"macros" which call methods on the ``Configurator`` object on your +behalf. + +ZCML Conflict Detection +~~~~~~~~~~~~~~~~~~~~~~~ + +An additional feature of ZCML is *conflict detection*. If you define +two declaration tags within the same ZCML file which logically +"collide", an exception will be raised, and the application will not +start. For example, the following ZCML file has two conflicting +```` tags: + +.. code-block:: xml + :linenos: + + + + + + + + + + + +If you try to use this ZCML file as the source of ZCML for an +application, a ``ConfigurationError`` will be raised when you attempt +to start the application with information about which tags might have +conflicted. + +.. _word_on_xml_namespaces: + +A Word On XML Namespaces +~~~~~~~~~~~~~~~~~~~~~~~~ + +Using the ``http://namespaces.repoze.org/bfg`` namespace as the +default XML namespace isn't strictly necessary; you can use a +different default namespace as the default. However, if you do, the +declaration tags which are defined by :mod:`repoze.bfg` such as the +```` declaration tag will need to be defined in such a way that +the XML parser that :mod:`repoze.bfg` uses knows which namespace the +:mod:`repoze.bfg` tags are associated with. For example, the +following files are all completely equivalent: + +.. topic:: Use of A Non-Default XML Namespace + + .. code-block:: xml + :linenos: + + + + + + + + + +.. topic:: Use of A Per-Tag XML Namespace Without A Default XML Namespace + + .. code-block:: xml + :linenos: + + + + + + + + + +For more information about XML namespaces, see `this older, but simple +XML.com article `_. + +Conclusions +----------- + +:mod:`repoze.bfg` allows an application to perform configuration tasks +either imperatively or declaratively. You can choose the mode that +best fits your brain as necessary. + +For more information about the API of the ``Configurator`` object, see +:ref:`configuration_module`. The equivalent ZCML declaration tags are +introduced in narrative documentation chapters as necessary. + -- cgit v1.2.3