Signals

Overview

Signals help you decouple applications by sending notifications when actions occur elsewhere in the appliation. In short, signals allow certain senders to notify subscribers that something happened.

Assembly uses Blinker to provide a fast dispatching system that allows any number of interested parties to subscribe to events, or “signals”.

Extension: Blinker


Usage

Import

from assembly import signal

Create a signal

Import and use the @signal decorator on the function to send signal from. It will add a @pre and @post decorators on that function to be used by other function that will listens it.

Whenever the function with the @signal get executed, all functions with @pre and @post will be executed before and after the @signal function is executed repectively.

from assembly import signal

@signal
def hello_world(name):
    return "Hello World %s" %s

Listens to a signal

Now hello_world has @hello_world.pre and @hello_world.post. These decorators can attached to functions.

@hello_world.pre
def before_hello_world(*a, **kw):
    """This will be executed before"""

@hello_world.post
def after_hello_world(result, *kw):
    """This will be executed after"""
    if result:
        print(result)

@hello_world.post
def after_another_hello_world(result, *kw):
    """This will be executed after"""
    if result:
        print(result)

Full Example

Now we can run the functions and our signals will be executed

from assembly import signal

# Emit the signal

@signal
def hello_world(name):
    return "Hello World %s" %s

# Listeners

@hello_world.pre
def before_hello_world(*a, **kw):
    """This will be executed before"""

@hello_world.post
def after_hello_world(result, *kw):
    """This will be executed after"""
    if result:
        print(result)

@hello_world.post
def after_another_hello_world(result, *kw):
    """This will be executed after"""
    if result:
        print(result)


hello_world('Assembly')
hello_world('Mardix')

API

@signal


@pre

Functions with @pre will be executed before the signaled functions is executed.

The function receiving the signal, must have 1 args:

- *a
- **kwargs: 
    args: *a,
    kwargs: **kw,
    name: the name of the signal,
    signal: the signal's instance

Example

@myfn.pre
def post_action(*a, **kw):
    pass

@post

Functions with @post will be executed after the signaled functions is finished.

The function receiving the signal, must have 2 args:

- result: that's the result sent from the signal
- **kwargs: 
    args: *a,
    kwargs: **kw,
    name: the name of the signal,
    signal: the signal's instance

Example

@myfn.post
def post_action(result, **kw):
    if result: 
        print("Done!")

@pre_ and @post_

To fully utilize Blinker functionalities, use post_ and pre_, for example @do_something.post_.connect, @do_something.pre_.connect