1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
.. index::
single: application configuration
.. _configuration_narr:
Application Configuration
=========================
Most people already understand "configuration" as settings that influence the
operation of an application. For instance, it's easy to think of the values in
a ``.ini`` file parsed at application startup time as "configuration". However,
if you're reasonably open-minded, it's easy to think of *code* as configuration
too. Since Pyramid, like most other web application platforms, is a
*framework*, it calls into code that you write (as opposed to a *library*,
which is code that exists purely for you to call). The act of plugging
application code that you've written into :app:`Pyramid` is also referred to
within this documentation as "configuration"; you are configuring
:app:`Pyramid` to call the code that makes up your application.
.. seealso::
For information on ``.ini`` files for Pyramid applications see the
:ref:`startup_chapter` chapter.
There are two ways to configure a :app:`Pyramid` application: :term:`imperative
configuration` and :term:`declarative configuration`. Both are described below.
.. index::
single: imperative configuration
.. _imperative_configuration:
Imperative Configuration
------------------------
"Imperative configuration" just means configuration done by Python statements,
one after the next. Here's one of the simplest :app:`Pyramid` applications,
configured imperatively:
.. code-block:: python
:linenos:
from wsgiref.simple_server import make_server
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()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
We won't talk much about what this application does yet. Just note that the
"configuration' statements take place underneath the ``if __name__ ==
'__main__':`` stanza in the form of method calls on a :term:`Configurator`
object (e.g., ``config.add_view(...)``). These statements take place one after
the other, and are executed in order, so the full power of Python, including
conditionals, can be employed in this mode of configuration.
.. index::
single: view_config
single: configuration decoration
single: code scanning
.. _decorations_and_code_scanning:
Declarative Configuration
-------------------------
It's sometimes painful to have all configuration done by imperative code,
because often the code for a single application may live in many files. If the
configuration is centralized in one place, you'll need to have at least two
files open at once to see the "big picture": the file that represents the
configuration, and the file that contains the implementation objects referenced
by the configuration. To avoid this, :app:`Pyramid` allows you to insert
:term:`configuration decoration` statements very close to code that is referred
to by the declaration itself. For example:
.. code-block:: python
:linenos:
from pyramid.response import Response
from pyramid.view import view_config
@view_config(name='hello', request_method='GET')
def hello(request):
return Response('Hello')
The mere existence of configuration decoration doesn't cause any configuration
registration to be performed. Before it has any effect on the configuration of
a :app:`Pyramid` application, a configuration decoration within application
code must be found through a process known as a :term:`scan`.
For example, the :class:`pyramid.view.view_config` decorator in the code
example above adds an attribute to the ``hello`` function, making it available
for a :term:`scan` to find it later.
A :term:`scan` of a :term:`module` or a :term:`package` and its subpackages for
decorations happens when the :meth:`pyramid.config.Configurator.scan` method is
invoked: scanning implies searching for configuration declarations in a package
and its subpackages. For example:
.. code-block:: python
:linenos:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config
@view_config()
def hello(request):
return Response('Hello')
if __name__ == '__main__':
config = Configurator()
config.scan()
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
The scanning machinery imports each module and subpackage in a package or
module recursively, looking for special attributes attached to objects defined
within a module. These special attributes are typically attached to code via
the use of a :term:`decorator`. For example, the
:class:`~pyramid.view.view_config` decorator can be attached to a function or
instance method.
Once scanning is invoked, and :term:`configuration decoration` is found by the
scanner, a set of calls are made to a :term:`Configurator` on your behalf.
These calls replace the need to add imperative configuration statements that
don't live near the code being configured.
The combination of :term:`configuration decoration` and the invocation of a
:term:`scan` is collectively known as :term:`declarative configuration`.
In the example above, the scanner translates the arguments to
:class:`~pyramid.view.view_config` into a call to the
:meth:`pyramid.config.Configurator.add_view` method, effectively:
.. code-block:: python
config.add_view(hello)
Summary
-------
There are two ways to configure a :app:`Pyramid` application: declaratively and
imperatively. You can choose the mode with which you're most comfortable; both
are completely equivalent. Examples in this documentation will use both modes
interchangeably.
|