Henson

Henson is a library for building services that are driven by consumers. Henson applications read from objects that implement the Consumer Interface and provide the message received to a callback for processing. The messsage can be processed before handing it off to the callback, and the callback’s results can be processed after they are returned to the application.

Note

This documentation uses the async/await syntax introduced to Python 3.5 by way of PEP 492. If you are using an older version of Python, replace async with the @asyncio.coroutine decorator and await with yield from.

Installation

You can install Henson using Pip:

$ python -m pip install henson

You can also install it from source:

$ python setup.py install

Quickstart

from henson import Abort, Application

class FileConsumer:
    """Read lines from a file."""

    def __init__(self, filename):
        self.filename = filename
        self._file = None

    def __iter__(self):
        """FileConsumer objects are iterators."""
        return self

    def __next__(self):
        """Return the next line of the file, if available."""
        if not self._file:
            self._file = open(self.filename)
        try:
            return next(self._file)
        except StopIteration:
            self._file.close()
            raise Abort('Reached end of file', None)

    async def read(self):
        """Return the next line in the file."""
        return next(self)

async def callback(app, message):
    """Print the message retrieved from the file consumer."""
    print(app.name, 'received:', message)
    return message

app = Application(
    __name__,
    callback=callback,
    consumer=FileConsumer(__file__),
)

@app.startup
async def print_header(app):
    """Print a header for the file being processed."""
    print('# Begin processing', app.consumer.filename)

@app.teardown
async def print_footer(app):
    """Print a footer for the file being processed."""
    print('# Done processing', app.consumer.filename)

@app.message_preprocessor
async def remove_comments(app, line):
    """Abort processing of comments (lines that start with #)."""
    if line.strip().startswith('#'):
        raise Abort('Line is a comment', line)
    return line

Running Applications

Henson provides a henson command to run your applications from the command line. To run the application defined in the quickstart above, cd to the directory containing the module and run:

$ henson run file_printer

Henson’s CLI can also be invoked by running the installed package as a script. To avoid confusion and prevent different installations of Henson from interfering with one another, this is the recommended way to run Henson applications:

$ python -m henson run file_printer

If a module contains only one instance of a Henson Application, python -m henson run will automatically detect and run it. If more than one instance exists, the desired application’s name must be specified:

$ python -m henson run file_printer:app

This form always takes precedence over the former, and the henson command won’t attempt to auto-detect an instance even if there is a problem with the name specified. If the attribute specified by the name after : is callable, python -m henson run will call it and use the returned value as the application. Any callable specified this way should require no arguments and return an instance of Application. Autodiscovery of callables that return applications is not currently supported.

More detailed information about Henson’s command line interface can be found in Command Line Interface.

Logging

Henson applications provide a default logger. The logger returned by calling logging.getLogger() will be used. The name of the logger is the name given to the application. Any configuration needed (e.g., logging.basicConfig(), logging.config.dictConfig(), etc.) should be done before the application is started.

Debug Mode

Debugging with asyncio can be tricky. Henson provides a debug mode enables asyncio’s debug mode as well as debugging information through Henson’s logger.

Debug mode can be enabled through a configuration setting:

app.settings['DEBUG'] = True

or by providing a truthy value for debug when calling run_forever():

app.run_forever(debug=True)

Contents:

Indices and tables