Doozer

Doozer is a library for building services that are driven by consumers. Doozer 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.

Installation

You can install Doozer using Pip:

$ python -m pip install doozer

You can also install it from source:

$ python setup.py install

Quickstart

from __future__ import annotations

from doozer 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

Doozer provides a doozer 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:

$ doozer run file_printer

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

$ python -m doozer run file_printer

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

$ python -m doozer run file_printer:app

This form always takes precedence over the former, and the doozer 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 doozer 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 Doozer’s command line interface can be found in Command Line Interface.

Logging

Doozer 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. Doozer provides a debug mode enables asyncio’s debug mode as well as debugging information through Doozer’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