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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
.. _scanning_chapter:
Configuration, Decorations And Code Scanning
============================================
:mod:`repoze.bfg` provides a number of "modes" for performing
application configuration. These modes can be used interchangeably or
even combined, as necessary.
For example:
- A ``<view>`` :term:`ZCML declaration` adds a :term:`view
configuration` to the current :term:`application registry`.
- A call to the :meth:`repoze.bfg.configuration.Configurator.add_view`
method adds a :term:`view configuration` to the current
:term:`application registry`.
- the :class:`repoze.bfg.view.bfg_view` :term:`decorator` adds
:term:`configuration decoration` to the function or method it
decorates. This particular decoration can result in a :term:`view
configuration` to be added to the current :term:`application
registry` if the package the code lives in is run through a
:term:`scan`.
.. index::
single: decorator
single: scan
Decorations and Code Scanning
-----------------------------
To lend more *locality of reference* to a :term:`configuration
declaration`, :mod:`repoze.bfg` allows you to insert
:term:`configuration decoration` statements very close to code that is
referred to by the declaration itself.
The mere existence of configuration decoration doesn't cause any
configuration registration to be made. Before they have any effect on
the configuration of a :mod:`repoze.bfg` application, a configuration
decoration within application code must be found through a process
known as *scanning*.
:mod:`repoze.bfg` is willing to :term:`scan` a module or a package and
its subpackages for decorations when the
:meth:`repoze.bfg.configuration.Configurator.scan` method is invoked:
scanning implies searching for configuration declarations in a package
and its subpackages. :term:`ZCML` can also invoke a :term:`scan` via
its ``<scan>`` directive.
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:`repoze.bfg.view.bfg_view` decorator can be
attached to a function or instance method:
.. code-block:: python
:linenos:
from repoze.bfg.view import bfg_view
from webob import Response
@bfg_view(name='hello', request_method='GET')
def hello(request):
return Response('Hello')
The :class:`repoze.bfg.view.bfg_view` decorator above simply adds an
attribute to the ``hello`` function, making it available for a
:term:`scan` to find it later.
Once scanning is invoked, and :term:`configuration decoration` is
found by the scanner, a set of calls are made to a
:term:`Configurator` on behalf of the developer: these calls represent
the intent of the configuration decoration. In the example above,
this is best represented as the scanner translating the arguments to
:class:`repoze.bfg.view.bfg_view` into a call to the
:meth:`repoze.bfg.configuration.Configurator.add_view` method,
effectively:
.. ignore-next-block
.. code-block:: python
config.add_view(hello, name='hello', request_method='GET')
Scanning for :term:`configuration decoration` is performed via the
:meth:`repoze.bfg.configuration.Configurator.scan` method or via a
``<scan>`` :term:`ZCML declaration`. See
:ref:`config_mode_equivalence` for examples.
.. index::
pair: configuration mode; equivalence
single: add_view
single: bfg_view
pair: ZCML directive; view
.. _config_mode_equivalence:
Configuration Mode Equivalence
------------------------------
A combination of imperative configuration, declarative configuration
via ZCML and scanning can be used to configure any application. Each
of the below examples produces the same application configuration.
.. topic:: Completely Imperative Configuration
.. code-block:: python
:linenos:
# helloworld.py
from repoze.bfg.view import bfg_view
from webob import Response
def hello(request):
return Response('Hello')
if __name__ == '__main__':
from repoze.bfg.configuration import Configurator
config = Configurator()
config.add_view(hello, name='hello', request_method='GET')
.. topic:: Configuration via ZCML
.. code-block:: python
:linenos:
# helloworld.py
from webob import Response
def hello(request):
return Response('Hello')
if __name__ == '__main__':
from repoze.bfg.configuration import Configurator
config = Configurator()
config.load_zcml('configure.zcml')
.. code-block:: xml
:linenos:
<configure xmlns="http://namespaces.repoze.org">
<!-- configure.zcml -->
<include package="repoze.bfg.includes"/>
<view name="hello"
request_method="GET"/>
</configure>
.. topic:: Using Decorations (Imperatively Starting a Scan)
.. code-block:: python
:linenos:
from repoze.bfg.view import bfg_view
from webob import Response
@bfg_view(name='hello', request_method='GET')
def hello(request):
return Response('Hello')
if __name__ == '__main__':
from repoze.bfg.configuration import Configurator
config = Configurator()
config.scan()
.. topic:: Using Decorations (Starting a Scan via ZCML)
.. code-block:: python
:linenos:
# helloworld.py
from repoze.bfg.view import bfg_view
from webob import Response
@bfg_view(name='hello', request_method='GET')
def hello(request):
return Response('Hello')
if __name__ == '__main__':
from repoze.bfg.configuration import Configurator
config = Configurator()
config.load_zcml('configure.zcml')
.. code-block:: xml
:linenos:
<configure xmlns="http://namespaces.repoze.org">
<!-- configure.zcml -->
<include package="repoze.bfg.includes"/>
<scan package="."/>
</configure>
|