summaryrefslogtreecommitdiff
path: root/repoze/bfg/events.py
blob: 22822eeebd514fb8ffbd8cab1c4fff27f2172b28 (plain)
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
import venusian

from zope.interface import implements

from repoze.bfg.interfaces import IAfterTraversal
from repoze.bfg.interfaces import INewRequest
from repoze.bfg.interfaces import INewResponse
from repoze.bfg.interfaces import IWSGIApplicationCreatedEvent

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
    instance has an attribute, ``request``, which is a :term:`request`
    object.  This 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` view returns a :term:`response`.
    The instance has an attribute, ``response``, which is the response
    object returned by the view.  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, response):
        self.response = response

class AfterTraversal(object):
    implements(IAfterTraversal)
    """ An instance of this class is emitted as an :term:`event` after
    the :mod:`repoze.bfg` :term:`router` 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 defined by the traverser.  This class implements
    the :class:`repoze.bfg.interfaces.IAfterTraversal` interface."""
    def __init__(self, request):
        self.request = request
    
class WSGIApplicationCreatedEvent(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.IWSGIApplicationCreatedEvent`
    interface."""
    implements(IWSGIApplicationCreatedEvent)
    def __init__(self, app):
        self.app = app
        self.object = app