Navigation

Although it is easy to use WSGI middleware with Pecan, it can be hard
(sometimes impossible) to have access to Pecan’s internals from within
middleware. Pecan Hooks are a way to interact with the framework,
without having to write separate middleware.

Hooks allow you to execute code at key points throughout the life cycle of your request:

on_route(): called before Pecan attempts to
route a request to a controller

on_route(), before(),
and after() are each passed a shared
state object which includes useful information, such as the request and
response objects, and which controller was selected by Pecan’s routing:

classSimpleHook(PecanHook):defon_route(self,state):print"\nabout to map the URL to a Python method (controller)..."assertstate.controllerisNone# Routing hasn't occurred yetassertisinstance(state.request,webob.Request)assertisinstance(state.response,webob.Response)assertisinstance(state.hooks,list)# A list of hooks to applydefbefore(self,state):print"\nabout to enter the controller..."ifstate.request.path=='/':## `state.controller` is a reference to the actual# `@pecan.expose()`-ed controller that will be routed to# and used to generate the response body#assertstate.controller.__func__isRootController.index.__func__assertisinstance(state.arguments,inspect.Arguments)printstate.arguments.argsprintstate.arguments.varargsprintstate.arguments.keywordsassertisinstance(state.request,webob.Request)assertisinstance(state.response,webob.Response)assertisinstance(state.hooks,list)

on_error() is passed a shared state object and
the original exception. If an on_error() handler
returns a Response object, this response will be returned to the end user and
no furthur on_error() hooks will be executed:

Now that SimpleHook is included, let’s see what happens
when we run the app and browse the application from our web browser.

pecan serve config.py
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
about to enter the controller...
DO SOMETHING!
method: GET
response: 200 OK

Hooks can be inherited from parent class or mixins. Just make sure to
subclass from HookController.

frompecanimportexposefrompecan.hooksimportPecanHook,HookControllerclassParentHook(PecanHook):priority=1defbefore(self,state):print"\nabout to enter the parent controller..."classCommonHook(PecanHook):priority=2defbefore(self,state):print"\njust a common hook..."classSubHook(PecanHook):defbefore(self,state):print"\nabout to enter the subcontroller..."classSubMixin(object):__hooks__=[SubHook()]# We'll use the same instance for both controllers,# to avoid double callscommon=CommonHook()classSubController(HookController,SubMixin):__hooks__=[common]@expose('json')defindex(self):print"\nI AM THE SUB!"returndict()classRootController(HookController):__hooks__=[common,ParentHook()]@expose('json')defindex(self):print"\nI AM THE ROOT!"returndict()sub=SubController()

Let’s see what happens when we run the app.
First loading the root controller:

pecan serve config.py
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
GET / HTTP/1.1" 200
about to enter the parent controller...
just a common hook
I AM THE ROOT!

Then loading the sub controller:

pecan serve config.py
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
GET /sub HTTP/1.1" 200
about to enter the parent controller...
just a common hook
about to enter the subcontroller...
I AM THE SUB!

Note

Make sure to set proper priority values for nested hooks in order
to get them executed in the desired order.

Warning

Two hooks of the same type will be added/executed twice, if passed as
different instances to a parent and a child controller.
If passed as one instance variable - will be invoked once for both controllers.

The items list specify the information that the hook will return.
Sometimes you will need a specific piece of information or a certain
bunch of them according to the development need so the defaults will
need to be changed and a list of items specified.

Note

When specifying a list of items, this list overrides completely the
defaults, so if a single item is listed, only that item will be returned by
the hook.

The hook has access to every single attribute the request object has
and not only to the default ones that are displayed, so you can fine tune the
information displayed.

These is a list containing all the possible attributes the hook has access to
(directly from webob):

accept

make_tempfile

accept_charset

max_forwards

accept_encoding

method

accept_language

params

application_url

path

as_string

path_info

authorization

path_info_peek

blank

path_info_pop

body

path_qs

body_file

path_url

body_file_raw

postvars

body_file_seekable

pragma

cache_control

query_string

call_application

queryvars

charset

range

content_length

referer

content_type

referrer

cookies

relative_url

copy

remote_addr

copy_body

remote_user

copy_get

remove_conditional_headers

date

request_body_tempfile_limit

decode_param_names

scheme

environ

script_name

from_file

server_name

from_string

server_port

get_response

str_GET

headers

str_POST

host

str_cookies

host_url

str_params

http_version

str_postvars

if_match

str_queryvars

if_modified_since

unicode_errors

if_none_match

upath_info

if_range

url

if_unmodified_since

urlargs

is_body_readable

urlvars

is_body_seekable

uscript_name

is_xhr

user_agent

make_body_seekable

And these are the specific ones from Pecan and the hook:

controller

hooks

params (params is actually available from webob but it is parsed
by the hook for redability)