Muffin is a fast, simple and asyncronous web-framework for Python 3
Python Makefile
Fetching latest commit…
Cannot retrieve the latest commit at this time.


The Muffin

Build Status

The Muffin -- A web framework based on Asyncio stack (early beta)

Muffin is a fast, simple and asyncronous web-framework for Python 3.

Docs are available at Pull requests with documentation enhancements and/or fixes are awesome and most welcome.

Example "Hello User" with the Muffin:

import muffin

app = muffin.Application('example')

@app.register('/', '/hello/{name}')
def hello(request):
    name = request.match_info.get('name', 'anonymous')
    return 'Hello %s!' % name

if __name__ == '__main__':

Save the script as and run it:

$ python3 run

Open, in your browser. Enjoy!


The list of some Muffin plugins (please make PR if you want to provide more):


  • python >= 3.4.1


You could find some tests here:


The Muffin should be installed using pip:

pip install muffin


See more in the example application sources. The application is deployed on Heroku:

Run example server locally:

$ make -C example run

And open in your browser.


Muffin gets configuration options from python files. You have to specify default configuration module name in your app initialization:

app = muffin.Application('myapp', CONFIG='config.debug')

This name could be overriden by MUFFIN_CONFIG environment variable:

$ MUFFIN_CONFIG=settings_local muffin example run

Which in its turn could be overriden by --config param of muffin command:

$ muffin --config=config.debug example run

Also you can define default config parameter values while initializing your application:

app = muffin.Application('myapp', DEBUG=True, ANY_OPTION='Here', ONE_MORE='Yes')
Base application options

Base Muffin options and default values:

# Configuration module
'CONFIG': 'config'

# Enable debug mode
'DEBUG': False

# Logging options
'ACCESS_LOG': '-',  # File path to access log, - to stderr
'ACCESS_LOG_FORMAT': '%a %l %u %t "%r" %s %b "%{Referrer}i" "%{User-Agent}i"',

'LOG_FORMAT': '%(asctime)s [%(process)d] [%(levelname)s] %(message)s'
'LOG_DATE_FORMAT': '[%Y-%m-%d %H:%M:%S %z]'

# List of enabled plugins

# Setup static files in development
'STATIC_PREFIX': '/static'
'STATIC_FOLDERS': ['static']

# Setup recognition of HTTPS requests through reverse proxy:
# to enable, provide a tuple of (header, value)
Configuring logging

You can define your logging configurations with Python dictConfig format and place in LOGGING conf:

    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'default': {
            'format': '%(asctime)s %(levelname)s %(name)s %(message)s'
    'handlers': {
        'logfile': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'my_log.log',
            'maxBytes': 50 * 1024 * 1024,
            'backupCount': 10
    'loggers': {
        '': {
            'handlers': ['logfile'],
            'level': 'ERROR'
        'project': {
            'level': 'INFO',
            'propagate': True,

To use just get logger with logging.getLogger():

import logging
logger = logging.getLogger('project')

CLI integration

Run in your shell:

$ muffin --help
Write a custom command
def hello(name, upper=False):
    """ Write command help text here.

    :param name:  Write your name
    :param upper: Use uppercase

    greetings = 'Hello %s!' % name
    if upper:
        greetings = greetings.upper()
$ muffin example hello --help

    Write command help text here.

    positional arguments:
    name        Write your name

    optional arguments:
    -h, --help  show this help message and exit
    --upper     Enable use uppercase
    --no-upper  Disable use uppercase

$ muffin example hello mike --upper



Setup tests

Set module path to your Muffin Application in pytest configuration file or use command line option --muffin-app.


$ py.test -xs --muffin-app example

Testing application

See examples:

import pytest

def test_async_code():
    from aiohttp import request
    response = yield from request('GET', '')
    text = yield from response.text()
    assert 'html' in text

def test_app(app):
    """ Get your app in your tests as fixture. """
    assert == 'my app name'
    assert app.cfg.MYOPTION == 'develop'

def test_view(client):
    """ Make HTTP request to your application. """
    response = client.get('/my-handler')
    assert 'mydata' in response.text


Use muffin command. By example:

$ muffin example run --workers=4

See muffin {APP} run --help for more info.

Bug tracker

If you have any suggestions, bug reports or annoyances please report them to the issue tracker at


Development of The Muffin happens at:



Licensed under a MIT license (See LICENSE)

If you wish to express your appreciation for the project, you are welcome to send a postcard to:

Kirill Klenov
pos. Severny 8-3
MO, Istra, 143500