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: