Flask-DropIn¶
The Flask-DropIn makes organizing large flask application easier. You can break your flask app to multiple dropins, which is a similiar concept as Django’s app. Flask-DropIn will automatically pick them up, and assemble different parts into your flask application.
Installation¶
Install with pip or easy_install. Pick one way you like most:
pip install flask-dropin
easy_install flask-dropin
pip install git+git://github.com/zh012/flask-dropin.git
or download the latest version from version control:
git clone https://github.com/zh012/flask-dropin.git
cd flask-dropin
python setup.py develop
Create a Flask application¶
Create a folder testapp, and a file app.py in the folder with following content:
from flask import Flask
from flask_dropin import DropInManager
app = Flask(__name__)
app.config['DROPINS'] = ['home']
dropin = DropInManager(app)
if __name__ == '__main__':
app.run(debug=True)
Create another file home.py in the same folder:
from flask import Blueprint, jsonify
web = Blueprint('home_web', __name__, url_prefix='/web')
@web.route('/')
def landing():
return 'Hello world!'
api = Blueprint('home_api', __name__, url_prefix='/api')
@api.route('/version')
def myprofile():
return jsonify(version='0.0.0')
blueprints = [web, api]
Run this app:
python app.py
Now, open the urls:
http://localhost:5000/web
http://localhost:5000/api/version
in browser, you will find that the blueprints are registered to the app automatically.
Dropin¶
Dropin, conceptually like a app in Django project, is usually a python module. It contains the definition of pieces of the flask app, which is called drops and assembled into the app by DropInManager. The following settings are used to configure the dropins for an appp.
DROPINS
A list of python modules name. They has to be located in python path in order to be importable. In a settings file, it may look like:
DROPINS = [ 'contrib.auth', 'articles', 'extensions.myplugin', ... ]
DROPINS_ITER
A callable which take app as the only parameter and return a list (or any iterable) of dropins name. It could be a set in the way:
from myapp import discover_dropins DROPINS_ITER = discover_dropins
or using python object path with format module_name:object_name:
DROPINS_ITER = 'myapp:discover_dropins'
With this setting, you can implement some auto dropin discovering machanism. For example, let’s define the discover_dropins in myapp.py like this:
import os def discover_dropins(app): for f in os.list(app.root_path): if f.startswith('dropin_') and f.endswith('.py'): yield f[:-3]
Then, all the modules in the root_path (make sure it is in python path) with name like dropin_foo.py would be automatically discovered and loaded by DropInManager, with no need to put it in DROPINS list manually.
If DROPINS and DROPINS_ITER are both configured. DropInManger will load the DROPINS first, and then load DROPINS_ITER.
Drops loader¶
Drops is a list of extensions to enriche the app features. Drops loader imports the drops from dropins, and register the extensions to flask app.
In order to be imported, the drops should be exposed to the loader following certain convension. Let’s take the blueprints as example.
- If the dropin is a python module, you can define a variable blueprints as a list of
blueprints. As shown in Create a Flask application.
- If the dropin is a python package, you can create a plueprints.py module in this
package, and define a variable __drops__ as a list of blueprints in this module.
Not only a list type, the blueprints could be any iterable.
- Even further the ‘blueprints’ could be any type of object which has a iterable
attribute __drops__. In this case, the blueprints.__drops__ will be the real blueprints list.
- The blueprints or blueprints.__drops__ can also be a callable. It will be called
with app as the only argument to get the real blueprints list.
Flask-DropIn defined loaders for five types of drops out of box. They are blueprints, middlewares, context_processors, models and services. The ways that each loader imports drops are pretty much the same. However, different drops are assembled into the app differently.
blueprints
Default loader: flask_dropin.BlueprintsLoader
No superise, the blueprints are registered to app by calling app.register_blueprint. But you can customize the url_prefix used for each blueprint with settings.
DROPIN_BLUEPRINTS_TRANSFORM = { '/web': '', '/api/v3': '/api', '*': None }
With the settings above, all blueprints with /web url prefix will be mounted to root, and /api/v3 to api. As the value of * is None, all blueprints with other url prefixes will be ignored.
If * was not shown in this setting, the other blueprintes would be registered as normal. The value of * can also be a function, take the blueprinte’s url_prefix as argument, and return the prefix used by app.register_blueprint.
middlewares
Default loader: flask_dropin.MiddlewaresLoader
A middleware is an python object which has one or more attributes with name before_request, after_request and teardown_request, and they will be registered to the given app respectively.
context_processors
Default loader: flask_dropin.ContextProcessorsLoader
A context_processor is a function (or callable) which could be registed by app.context_processor.
models
The models loader stores model objects in
app.extensions['dropin']['models']
Default loader: flask_dropin.ModelsLoader
The default loader stores model objects into a list.
Other loader: ‘flask_dropin.nameddrops.NamedModelsLoader’
This loader stores model objects in a flask_dropin.nameddrops.DotDict object, where you can use the dotted notation to access the values.
services
The services loader stores service objects in
`app.extensions['dropin']['services']`
Default loader: flask_dropin.ServicesLoader
The default loader stores model objects into a list.
Other loader: ‘flask_dropin.nameddrops.NamedServicesLoader’
This loader stores service objects in a flask_dropin.nameddrops.DotDict object, where you can use the dotted notation to access the values.
Customize loaders¶
The setting DROPS_LOADERS is used for customize the loaders. The default setting is
DROPS_LOADERS = [
'flask_dropin:ModelsLoader',
'flask_dropin:BlueprintsLoader',
'flask_dropin:MiddlewaresLoader',
'flask_dropin:ContextProcessorsLoader',
'flask_dropin:ServicesLoader',
]
Your configuration will overwrite the default setting. The following setting will lead to only the blueprints being loaded.
DROPS_LOADERS = ['flask_dropin:BlueprintsLoader']
You create your own customized loaders to fit your needs and support new drops type.
Dropin manager¶
flask_dropin.DropInManager is a typical flask extensions. It intialize app in two flavors
dropin = DropInManager(app)
or
dropin = DropInManager()
dropin.init(app)
Other than that, it provides a shortcut to access the values that the loades stored in each app. In another word, it is a proxy to app.extensions[‘dropin’] dict. For example, you can use dropin.models to access the models list stored in the app by loader.
Thus, it helps to decouple the dropins from each other by avoiding explicitly import from other dropins, which makes the dropin swappable easily.
Continue with the app created in in Create a Flask application. Saying we have a new dropin auth.py
from flask import session
def login_user(name):
session['_user_name'] = name
def logout_user():
session['_user_name'] = None
def get_current_user():
return session.get('_user_name')
services = [login_user, logout_user, get_current_user]
and update the app config in app.py with
app.config['SECRET_KEY'] = 'secret'
app.config['DROPINS'] = ['home', 'auth']
app.config['DROPS_LOADERS'] = [
'flask_dropin:BlueprintsLoader',
'flask_dropin.nameddrops:NamedServicesLoader']
app.config['DROPIN_BLUEPRINTS_TRANSFORM'] = {'/web': ''}
then we can send a warmer greeting to the user by update the blueprint web in home.py
from flask import redirect, url_for
from app import dropin
@web.route('/')
def landing():
return 'Hello {}!'.format(dropin.services.get_current_user())
@web.route('/login/<username>')
def login_me(username):
dropin.services.login_user(username)
return redirect(url_for('.landing'))
@web.route('/logout')
def logout_me():
dropin.services.logout_user()
return redirect(url_for('.landing'))
Api¶
-
class
flask_dropin.
DropInManager
(app=None)[source]¶ A flask extension to initialize flask app with activated dropins, and also provide shortcut to access drops object if available.
Its behavior is controled by three settings.
DROPINS: a list of python object path for ativated dropins.
DROPINS_ITER: a callable (or python path to the callable) which return a list of dropins.
DROPS_LOADERS: a list of drops loader (or python path to drops loader). If not provided, ther following loaders will be used:
[ flask_dropin.ModelsLoader, flask_dropin.BlueprintsLoader, flask_dropin.MiddlewaresLoader, flask_dropin.ContextProcessorsLoader, flask_dropin.ServicesLoader, ]
- Usage:
Same as other flask extensions, DropInManager could be used in two flavors:
dropin = DropInManager(app)
or:
dropin = DropInManager() dropin.init(app)
-
class
flask_dropin.
BaseDropsLoader
(app)[source]¶ Load drops from python source code and register those to flask app. Base class of other loaders.
-
drops_type
¶ string
The name of drops type. It is used to locate the drops.
-
load_drops
(dropin)[source]¶ Load drops from the given dropin.
Parameters: dropin (string) – path of a dropin, e.g. dropin.auth Returns: An iterable contains the drops object in the given dropin This method load drops object by some sort of convension. For example, assuming we want to load drops type models from dropin dropin.articls. The drops are discoveried with the following sequence:
import dropin.articles drops = dropin.articles.models
if anything goes wrong, next try is
import dropin.articles.models as drops
if the current drops object has attribute __drops__
drops = drops.__drops__
if the current drops object is a callable
drops = drops()
if not drops was found, an empty list is returned.
-
register_drops
(dropin)[source]¶ Register the drops in given dropin to a flask app.
Parameters: - app (Flask) – the flask app to be initialized
- dropin (string) – path of a python module or object, e.g. dropin.auth
This is the only method that a drops loader must implment. The default behavior in the base loader is to store all the drops object in the app’s extentions dict.
For example, the drops with type models will be stored in a list which is accessible through:
app.extensions['dropin']['models']
or through DropInManager instance which provide a simple proxy to the dropin extension of current_app:
dropin = DropInManager() dropin.models
Whereas the BlueprintsLoader overrided this method to actually register the blueprints to the app.
-
-
class
flask_dropin.
BlueprintsLoader
(app)[source]¶ Load drops with type blueprints, and register blueprints to flask app.
-
class
flask_dropin.
MiddlewaresLoader
(app)[source]¶ Load drops with type middlewares, and register middlewares to flask app.
The before_request, after_request and teardown_request attributes will be registered to the given app respectively.
-
class
flask_dropin.
ContextProcessorsLoader
(app)[source]¶ Load drops with type context_processors, and register context_processors to flask app.
-
class
flask_dropin.nameddrops.
NamedModelsLoader
(app)[source]¶ Load drops with type models. The difference with to ModelsLoader is that this loader require the drops to be provided by name/value pairs. These models will be stored in a DotDict object, so that it could be referenced by dotted notation. In addition, it will check if there is name conflict among the models provided by each dropin.
Changes¶
Version 0.0.1¶
- Initial public release