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 https://muffin.readthedocs.org/. 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__':
app.manage()
Save the script as example.py and run it:
$ python3 example.py run
Open http://fuf.me:5000, http://fuf.me:5000/hello/username in your browser. Enjoy!
Contents
The list of some Muffin plugins (please make PR if you want to provide more):
Muffin-Admin -- Basic Admin interface
Muffin-Babel -- Localization support
Muffin-DebugToolbar -- Debug Toolbar
Muffin-Jade -- Jade templates
Muffin-Jinja2 -- Jinja2 templates
Muffin-Metrics -- Send metrics to Graphite/Statsd
Muffin-Mongo -- MongoDB (pymongo) support
Muffin-Motor -- MongoDB (motor) support
Muffin-OAuth -- OAuth client
Muffin-Peewee -- Peewee support (SQL, ORM)
Muffin-REST -- Helpers for building REST API
Muffin-Redis -- Redis support
Muffin-Sentry -- Sentry integration
Muffin-Session -- User session (auth)
- python >= 3.4.1
You could find some tests here: http://klen.github.io/py-frameworks-bench/
The Muffin should be installed using pip:
pip install muffin
See more in the example application sources. The application is deployed on Heroku: https://muffin-py.herokuapp.com
Run example server locally:
$ make -C example run
And open http://fuf.me:5000 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 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_LEVEL': 'WARNING'
'LOG_FORMAT': '%(asctime)s [%(process)d] [%(levelname)s] %(message)s'
'LOG_DATE_FORMAT': '[%Y-%m-%d %H:%M:%S %z]'
# List of enabled plugins
'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)
'SECURE_PROXY_SSL_HEADER': None
You can define your logging configurations with Python dictConfig format and place in LOGGING
conf:
LOGGING = {
'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')
Run in your shell:
$ muffin path.to.your.module:app_object_name --help
@app.manage.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()
print(greetings)
$ 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 HELLO MIKE!
Set module path to your Muffin Application in pytest configuration file or use
command line option --muffin-app
.
Example:
$ py.test -xs --muffin-app example
See examples:
import pytest
@pytest.mark.async
def test_async_code():
from aiohttp import request
response = yield from request('GET', 'http://google.com')
text = yield from response.text()
assert 'html' in text
def test_app(app):
""" Get your app in your tests as fixture. """
assert app.name == '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.
If you have any suggestions, bug reports or annoyances please report them to the issue tracker at https://github.com/klen/muffin/issues
Development of The Muffin happens at: https://github.com/klen/muffin
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 Russia