Using Events¶
An event is an object broadcast by the Pyramid framework at interesting points during the lifetime of an application. You don't need to use events in order to create most Pyramid applications, but they can be useful when you want to perform slightly advanced operations. For example, subscribing to an event can allow you to run some code as the result of every new request.
Events in Pyramid are always broadcast by the framework. However, they only become useful when you register a subscriber. A subscriber is a function that accepts a single argument named event:
1def mysubscriber(event):
2 print(event)
The above is a subscriber that simply prints the event to the console when it's called.
The mere existence of a subscriber function, however, is not sufficient to
arrange for it to be called. To arrange for the subscriber to be called,
you'll need to use the pyramid.config.Configurator.add_subscriber()
method or you'll need to use the pyramid.events.subscriber()
decorator to
decorate a function found via a scan.
Configuring an Event Listener Imperatively¶
You can imperatively configure a subscriber function to be called for some
event type via the add_subscriber()
method:
1from pyramid.events import NewRequest
2
3from subscribers import mysubscriber
4
5# "config" below is assumed to be an instance of a
6# pyramid.config.Configurator object
7
8config.add_subscriber(mysubscriber, NewRequest)
The first argument to add_subscriber()
is
the subscriber function (or a dotted Python name which refers to a
subscriber callable); the second argument is the event type.
See also
See also Configurator.
Configuring an Event Listener Using a Decorator¶
You can configure a subscriber function to be called for some event type via
the pyramid.events.subscriber()
function.
1from pyramid.events import NewRequest
2from pyramid.events import subscriber
3
4@subscriber(NewRequest)
5def mysubscriber(event):
6 event.request.foo = 1
When the subscriber()
decorator is used, a scan
must be performed against the package containing the decorated function for the
decorator to have any effect.
Either of the above registration examples implies that every time the
Pyramid framework emits an event object that supplies an
pyramid.events.NewRequest
interface, the mysubscriber
function
will be called with an event object.
As you can see, a subscription is made in terms of a class (such as
pyramid.events.NewResponse
). The event object sent to a subscriber
will always be an object that possesses an interface. For
pyramid.events.NewResponse
, that interface is
pyramid.interfaces.INewResponse
. The interface documentation provides
information about available attributes and methods of the event objects.
The return value of a subscriber function is ignored. Subscribers to the same event type are not guaranteed to be called in any particular order relative to each other.
All the concrete Pyramid event types are documented in the pyramid.events API documentation.
An Example¶
If you create event listener functions in a subscribers.py
file in your
application like so:
1def handle_new_request(event):
2 print('request', event.request)
3
4def handle_new_response(event):
5 print('response', event.response)
You may configure these functions to be called at the appropriate times by adding the following code to your application's configuration startup:
1# config is an instance of pyramid.config.Configurator
2
3config.add_subscriber('myproject.subscribers.handle_new_request',
4 'pyramid.events.NewRequest')
5config.add_subscriber('myproject.subscribers.handle_new_response',
6 'pyramid.events.NewResponse')
Either mechanism causes the functions in subscribers.py
to be registered as
event subscribers. Under this configuration, when the application is run, each
time a new request or response is detected, a message will be printed to the
console.
Each of our subscriber functions accepts an event
object and prints an
attribute of the event object. This begs the question: how can we know which
attributes a particular event has?
We know that pyramid.events.NewRequest
event objects have a
request
attribute, which is a request object, because the interface
defined at pyramid.interfaces.INewRequest
says it must. Likewise, we
know that pyramid.interfaces.NewResponse
events have a response
attribute, which is a response object constructed by your application, because
the interface defined at pyramid.interfaces.INewResponse
says it must
(pyramid.events.NewResponse
objects also have a request
).
Creating Your Own Events¶
In addition to using the events that the Pyramid framework creates, you can create your own events for use in your application. This can be useful to decouple parts of your application.
For example, suppose your application has to do many things when a new document is created. Rather than putting all this logic in the view that creates the document, you can create the document in your view and then fire a custom event. Subscribers to the custom event can take other actions, such as indexing the document, sending email, or sending a message to a remote system.
An event is simply an object. There are no required attributes or method for your custom events. In general, your events should keep track of the information that subscribers will need. Here are some example custom event classes:
1class DocCreated(object):
2 def __init__(self, doc, request):
3 self.doc = doc
4 self.request = request
5
6class UserEvent(object):
7 def __init__(self, user):
8 self.user = user
9
10class UserLoggedIn(UserEvent):
11 pass
Some Pyramid applications choose to define custom events classes in an
events
module.
You can subscribe to custom events in the same way that you subscribe to Pyramid events—either imperatively or with a decorator. You can also use custom events with subscriber predicates. Here's an example of subscribing to a custom event with a decorator:
1from pyramid.events import subscriber
2from .events import DocCreated
3from .index import index_doc
4
5@subscriber(DocCreated)
6def index_doc(event):
7 # index the document using our application's index_doc function
8 index_doc(event.doc, event.request)
The above example assumes that the application defines a DocCreated
event
class and an index_doc
function.
To fire your custom events use the pyramid.registry.Registry.notify()
method, which is most often accessed as request.registry.notify
. For
example:
1from .events import DocCreated
2
3def new_doc_view(request):
4 doc = MyDoc()
5 event = DocCreated(doc, request)
6 request.registry.notify(event)
7 return {'document': doc}
This example view will notify all subscribers to the custom DocCreated
event.
Note that when you fire an event, all subscribers are run synchronously so it's generally not a good idea to create event handlers that may take a long time to run. Although event handlers could be used as a central place to spawn tasks on your own message queues.