rapidsms.contrib.handlers

The handlers contrib application provides three classes- BaseHandler, KeywordHandler, and PatternHandler– which can be extended to help you create RapidSMS applications quickly.

 

Installation

To define and use handlers for your RapidSMS project, you will need to add "rapidsms.contrib.handlers" to INSTALLED_APPS in your settings file:

INSTALLED_APPS = [
    ...
    "rapidsms.contrib.handlers",
    ...
]

This application will load handlers according to the configuration parameters defined in your settings, as described in handlers discovery.

 

Usage

 

KeywordHandler

Many RapidSMS applications operate based on whether a message begins with a specific keyword. By subclassing KeywordHandler, you can easily create a simple, keyword-based application:

from rapidsms.contrib.handlers import KeywordHandler
class LightHandler(KeywordHandler):
    keyword = "light"
    def help(self):
        self.respond("Send LIGHT ON or LIGHT OFF.")
    def handle(self, text):
        if text.upper() == "ON":
            self.respond("The light is now turned on.")
        elif text.upper() == "OFF":
            self.respond("Thanks for turning off the light!")
        else:
            self.help()

Your handler must define three things: keyword, help(), and handle(text). When a message is received that begins with the keyword (case insensitive; leading whitespace is allowed), the remaining text is passed to the handle method of the class. If no additional non-whitespace text is included with the message, help is called instead. For example:

> light
< Send LIGHT ON or LIGHT OFF.
> light on
< The light is now turned on.
> light off
< Thanks for turning off the light!
> light something else
< Send LIGHT ON or LIGHT OFF.

Tip

Technically speaking, the incoming message text is compared to a regular expression pattern:

pattern = re.compile(r"^s*(?:%s)(?:[s,;:]+(.+))?$" % keyword,
                     re.IGNORECASE)

The most common use case is to look for a single exact-match keyword. However, one could also match multiple keywords, for example keyword = "register|reg|join".

All non-matching messages are silently ignored to allow other applications and handlers to catch them.

For example implementations of KeywordHandler, see

 

PatternHandler

The PatternHandler class can be subclassed to create applications which respond to a message when a specific pattern is matched:

from rapidsms.contrib.handlers import PatternHandler
class SumHandler(PatternHandler):
    pattern = r"^(d+) plus (d+)$"
    def handle(self, a, b):
        a, b = int(a), int(b)
        total = a + b
        self.respond("%d + %d = %d" % (a, b, total))

Your handler must define pattern and handle(*args). The pattern is case-insensitive, but must otherwise be matched precisely as written (for example, the handler pattern written above would not accept leading or trailing whitespace, but the pattern r"^(d+) plus (d+)s*$" would allow trailing whitespace). When the pattern is matched, the handle method is called with the captures as arguments. As an example, the above handler could create the following conversation:

> 1 plus 2
< 1 + 2 = 3

Like KeywordHandler, each PatternHandler silently ignores all non-matching messages to allow other handlers and applications to catch them.

 

BaseHandler

All handlers, including the KeywordHandler and PatternHandler, are derived from the BaseHandler class. When extending from BaseHandler, one must always override the class method dispatch, which should return True when it handles a message.

All instances of BaseHandler have access to self.msg and self.router, as well as the methods self.respond and self.respond_error (which respond to the instance’s message).

BaseHandler also defines the class method test, which creates a simple environment for testing a handler’s response to a specific message text. If the handler ignores the message then False is returned. Otherwise a list containing the text property of each OutgoingMessage response, in the order which they were sent, is returned. (Note: the list may be empty.) For example:

>>> from rapidsms.contrib.echo.handlers.echo import EchoHandler
>>> EchoHandler.test("not applicable")
False
>>> EchoHandler.test("echo hello!")
["hello!"]

For an example implementation of a BaseHandler, see rapidsms.contrib.echo.handlers.ping.PingHandler.

 

Calling Handlers

When a message is received, the handlers application calls dispatch on each of the handlers it loaded during handlers discovery.

The first handler to accept the message will block all others. The order in which the handlers are called is not guaranteed, so each handler should be as conservative as possible when choosing to respond to a message.

 

Handler Discovery

Handlers may be defined in the handlers subdirectory of any Django app listed in INSTALLED_APPS. Each file in the handlers subdirectory is expected to contain exactly one new-style Python class which extends from one of the core handler classes.

Handler discovery, which occurs when the handlers application is loaded, can be configured using the following project settings:

  • RAPIDSMS_HANDLERS_EXCLUDE_APPS – The application will not load handlers from any Django app included in this list.
  • INSTALLED_HANDLERS – If this list is not None, the application will load only handlers in modules that are included in this list.
  • EXCLUDED_HANDLERS – The application will not load any handler in a module that is included in this list.

Previous topic

Frequently Asked Questions

This Page