Testing Site Testing Site

skip to navigation
skip to content

django-foxhooks 0.1.1

Hooks for Django with priorities and integration in templates

Hooks for Django featuring priorities, integration in templates, and custom handler (yet provided: Once, Delay).

Overview

Hook instances are managed by the Hooks class, and holds the handlers of a specific event. Handler contains priority informations and the listener called when trigerred.

In foxhooks, there are two different kinds of priority: regular and reverse. Regular is always executed before reverse and from the lowest to the highest priority value. Reverse is executed in the opposite order. This allows registering handlers that are guaranteed to be executed after all the other ones.

# register using register function
def print_square(handler, x):
    print("square", x*x)
    return x*x

Hooks.register('some.event', square, priority = 0)

# register using decorators
@register('some.event')
def print_sum(handler, x):
    print("sum", x+x)
    return x+x

# triggers handlers registered for 'some.event'
r = Hooks.trigger('some.event', 5)
print(r)

Outputs:

square 25
sum 10
None

Result of listener functions calls can be collected as a list:

r = Hooks.trigger('some.event', 10, collect = True)
print(r)

Outputs:

[100, 20]

There also are special handlers, such as the Once handler. Example using the decorator (I’m too lazy for a more complete example in this overview):

@once('calc')
def sub(handler, x):
    return x*x - x

# this will trigger sub()
Hooks.trigger('calc', 13)
# this won't -- sub() has been unregistered after first trigger
Hooks.trigger('calc', 13)

Handler registration

It is possible to register an handler by passing a function or an Handler instance (or of its subclasses). In the first case, Handler will be instanciated using given arguments; otherwise those values will be dropped.

def a(handler, *args, **kwargs):
    print('a:', args, kwargs)

def b(handler, *args, **kwargs):
    print('b:', args, kwargs)

# register directly with a function
ha = Hooks.register('test', a)

# we can also specify a reverse priority at 0
hb = Hooks.register('test', b, priority = 0, reverse = True)

An Handler can only be registered once per hook. A function however can be reused for a different priority (in this case it instanciates a new Handler).

Hooks.register('test', ha)          # fails: ha yet present
Hooks.register('test', ha, 12)      # fails: ha yet present
Hooks.register('test', a)           # okay: new instance created
Hooks.register('test', a, 12)       # okay: new instance created

Different Handler subclasses

We provide different subclass for Handlers that might be usefull in foxhooks.handlers:

  • Delay: triggers only if event happened with a given minimal time delay since previous one;
  • Once: triggers only once; after that, unregister itself from the hook;

Decorator

In order to simplify life in some cases, function decorators are provided:

  • @register: register the function to the given hook;
  • @once: register the function using a Once handler;
  • @delay: register the function using a Delay handler;

Template

It is also possible to use hooks in django’s templates. The results of the trigger will be concatenated as a list of string rendered in the template. Results that are not SafeString will be escaped.

Here is a simple example, that triggers admin.object.actions for each object of object_list in the template.

Template

{% load foxhooks %}

{% for object in object_list %}
    {# ... #}
    <div class="actions">
        {% hook "admin.object.actions" object=object %}
    </div>
{% endfor %}

Python

import django.utils.html as html

def action_edit(handler, object):
    return html.format_html('<a href="/edit/{}">Edit</a>',
                            object.pk);

def action_del(handler, object):
    return html.format_html('<a href="/del/{}">Delete</a>',
                            object.pk);

Hooks.register('admin.object.actions', action_edit)
Hooks.register('admin.object.actions', action_del)

Outputs (where {pk} is the object primary key value):

<!-- for each object in object_list -->
    <!-- ... -->
    <div class="actions">
        <a href="/edit/{pk}">Edit</a>
        <a href="/del/{pk}">Delete</a>
    </div>

Tips & Infos

Un-Register in an triggering hook

When a trigger() loop is running on a Hook, un-registration of handlers will be delayed to the end of the loop. However, the to-be registered Handler still is returned by the register method.

def register_in_loop(handler):
    # registration will be delayed after the running trigger loop
    handler = Hooks.register('test.in_loop', a)
    return 1

Hooks.register('test.in_loop', register_in_loop)

# only run register_in_loop()
Hooks.trigger('test.in_loop')

# run register_in_loop() and a()
Hooks.trigger('test.in_loop')

Error handling

When an error occurs during a trigger, the running loop is interrupted. However, delayed un-registration are done.

 
File Type Py Version Uploaded on Size
django-foxhooks-0.1.1.tar.gz (md5) Source 2018-01-12 10KB