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
203
204
205
206
207
208
209
|
import venusian
from zope.interface import implements
from repoze.bfg.interfaces import IContextFound
from repoze.bfg.interfaces import INewRequest
from repoze.bfg.interfaces import INewResponse
from repoze.bfg.interfaces import IApplicationCreated
from repoze.bfg.interfaces import IFinishedRequest
class subscriber(object):
""" Decorator activated via a :term:`scan` which treats the
function being decorated as an event subscriber for the set of
interfaces passed as ``*ifaces`` to the decorator constructor.
For example:
.. code-block:: python
from repoze.bfg.interfaces import INewRequest
from repoze.bfg.events import subscriber
@subscriber(INewRequest)
def mysubscriber(event):
event.request.foo = 1
More than one event type can be passed as a construtor argument:
.. code-block:: python
from repoze.bfg.interfaces import INewRequest
from repoze.bfg.events import subscriber
@subscriber(INewRequest, INewResponse)
def mysubscriber(event):
print event
When the ``subscriber`` decorator is used without passing an arguments,
the function it decorates is called for every event sent:
.. code-block:: python
from repoze.bfg.interfaces import INewRequest
from repoze.bfg.events import subscriber
@subscriber()
def mysubscriber(event):
print event
This method will have no effect until a :term:`scan` is performed
against the package or module which contains it, ala:
.. code-block:: python
from repoze.bfg.configuration import Configurator
config = Configurator()
config.scan('somepackage_containing_subscribers')
"""
venusian = venusian # for unit testing
def __init__(self, *ifaces):
self.ifaces = ifaces
def register(self, scanner, name, wrapped):
config = scanner.config
config.add_subscriber(wrapped, self.ifaces)
def __call__(self, wrapped):
self.venusian.attach(wrapped, self.register, category='bfg')
return wrapped
class NewRequest(object):
""" An instance of this class is emitted as an :term:`event`
whenever :mod:`repoze.bfg` begins to process a new request. The
even instance has an attribute, ``request``, which is a
:term:`request` object. This event class implements the
:class:`repoze.bfg.interfaces.INewRequest` interface."""
implements(INewRequest)
def __init__(self, request):
self.request = request
class NewResponse(object):
""" An instance of this class is emitted as an :term:`event`
whenever any :mod:`repoze.bfg` :term:`view` or :term:`exception
view` returns a :term:`response`.
The instance has two attributes:``request``, which is the request
which caused the response, and ``response``, which is the response
object returned by a view or renderer.
If the ``response`` was generated by an :term:`exception view`,
the request will have an attribute named ``exception``, which is
the exception object which caused the exception view to be
executed. If the response was generated by a 'normal' view, the
request will not have this attribute.
This event will not be generated if a response cannot be created
due to an exception that is not caught by an exception view (no
response is created under this circumstace).
This class implements the
:class:`repoze.bfg.interfaces.INewResponse` interface.
.. note::
Postprocessing a response is usually better handled in a WSGI
:term:`middleware` component than in subscriber code that is
called by a :class:`repoze.bfg.interfaces.INewResponse` event.
The :class:`repoze.bfg.interfaces.INewResponse` event exists
almost purely for symmetry with the
:class:`repoze.bfg.interfaces.INewRequest` event.
"""
implements(INewResponse)
def __init__(self, request, response):
self.request = request
self.response = response
class ContextFound(object):
implements(IContextFound)
""" An instance of this class is emitted as an :term:`event` after
the :mod:`repoze.bfg` :term:`router` finds a :term:`context`
object (after it performs traversal) but before any view code is
executed. The instance has an attribute, ``request``, which is
the request object generated by :mod:`repoze.bfg`.
Notably, the request object will have an attribute named
``context``, which is the context that will be provided to the
view which will eventually be called, as well as other attributes
attached by context-finding code.
This class implements the
:class:`repoze.bfg.interfaces.IContextFound` interface.
.. note:: As of :mod:`repoze.bfg` 1.3, for backwards compatibility
purposes, this event may also be imported as
:class:`repoze.bfg.events.AfterTraversal`.
"""
def __init__(self, request):
self.request = request
AfterTraversal = ContextFound # b/c as of 1.3
class ApplicationCreated(object):
""" An instance of this class is emitted as an :term:`event` when
the :meth:`repoze.bfg.configuration.Configurator.make_wsgi_app` is
called. The instance has an attribute, ``app``, which is an
instance of the :term:`router` that will handle WSGI requests.
This class implements the
:class:`repoze.bfg.interfaces.IApplicationCreated` interface.
.. note:: For backwards compatibility purposes, this class can
also be imported as
:class:`repoze.bfg.events.WSGIApplicationCreatedEvent`. This
was the name of the event class before :mod:`repoze.bfg` 1.3.
"""
implements(IApplicationCreated)
def __init__(self, app):
self.app = app
self.object = app
WSGIApplicationCreatedEvent = ApplicationCreated # b/c (as of 1.3)
class FinishedRequest(object):
"""
This :term:`event` is sent after all request processing is
finished.
An event of this type is emitted unconditionally at the end of
request processing, even when an unhandled exception occurs. This
is in contrast to the :class:`repoze.bfg.interfaces.INewResponse`
event, which cannot be emitted when, due to an unhandled
exception, a response object cannot not be created . The
:class:`repoze.bfg.events.FinishedRequest` event will even be sent
when a request cannot not be created due to an error in request
factory code: in such a case, the ``request`` attribute of the
event will be ``None``.
Mutating the attached ``request`` object in a subscriber to this
event will have no effect, because, when this event is emitted,
there is no further request or response processing to be done. It
is purely an informational event, which can be hooked to do
'finally:'-style tear-down at the end of each request.
Instances of this event have an attribute, ``request``, which is
the :term:`request` object (or, in extremely rare cases might be
``None``, when a request object cannot be created due to a bug in
a request factory) .
Because this event happens unconditionally, the set of attributes
possessed by an attached ``request`` object are indeterminate. At
very least, if the request is not ``None``, it will have a
``registry`` attribute. However, if an exception was thrown
before this event is broadcast, it may not have other
:mod:`repoze.bfg` -specific attributes such as ``subpath``,
``root`, ``traversed``, etc.
Exceptions raised by subscribers of this event are unhandled.
This class implements the
:class:`repoze.bfg.interfaces.IFinishedRequest` interface.
.. note:: This event type is new as of :mod:`repoze.bfg` 1.3.
"""
implements(IFinishedRequest)
def __init__(self, request):
self.request = request
|