Adds Injector support to Flask.
Project description
Adds Injector support to Flask.
Injector is a dependency-injection framework for Python, inspired by Guice.
This brings several benefits to Flask:
No need for a global “app” object, or globals in general. This makes testing simpler.
Explicit assignment of routes at app construction time.
Class-based routes with injected arguments.
Typical application layout
The first step is generally to create views. Views are global functions or classes marked with the @route decorator (t has the same arguments as Flask’s @app.route decorator). Views can have dependencies injected into them as keyword arguments by using the Injector.inject decorator:
import sqlite3 from flask.ext.injector import FlaskInjector, route from flask import Config from injector import inject @route("/bar") def bar(): return render("bar.html") # Route with injection @route("/foo") @inject(db=sqlite3.Connection) def foo(db): users = db.execute('SELECT * FROM users').all() return render("foo.html") # Class-based route with injected constructor @route('/waz') class Waz(object): @inject(db=sqlite3.Connection) def __init__(self, db): self.db = db @route("/waz/<key>") def waz(self, key): users = db.execute('SELECT * FROM users WHERE name=?', (key,)).all() return 'waz'
In the Injector world, all dependency configuration and initialization is performed in modules. The same is true with Flask-Injector. You can see some examples of configuring Flask extensions through modules below.
Accordingly, the next step is to create modules for any objects we want made available to the application. Note that in this example we also use the injector to gain access to the flask.Config, which is bound by FlaskInjector:
# Configure our SQLite connection object @inject(config=Config) def configure(binder, config): binder.bind( sqlite3.Connection, to=sqlite3.Connection(config['DB_CONNECTION_STRING']), scope=request, )
Instantiate the Flask instance in main():
def main(): app = Flask(__name__)
Update the Flask app configuration as normal, additionally passing in any configuration for modules:
app.config.update( DB_CONNECTION_STRING=':memory:', )
Create a list of view functions and classes to install into the application:
views = [foo, bar, Waz]
Create a list of Injector modules to use for configuring the application state:
modules = [configure]
Construct a FlaskInjector instance, passing the view list and module list to the constructor, and initialize the application with it:
flask_injector = FlaskInjector(views, modules) injector = flask_injector.init_app(app)
Run the Flask application as normal:
app.run()
See example.py for a more complete example, including Flask-SQLAlchemy and Flask-Cache integration.
Supporting Flask Extensions
Typically, Flask extensions are initialized at the global scope using a pattern similar to the following.
app = Flask(__name__) ext = ExtClass(app) @app.route(...) def view(): # Use ext object here...
As we don’t have these globals with Flask-Injector we have to configure the extension the Injector way - through modules. Modules can either be subclasses of injector.Module or a callable taking an injector.Binder instance.
@inject(app=Flask) def configure_ext(binder, app): binder.bind(ExtClass, to=ExtClass(app), scope=singleton) def main(): app = Flask(__name__) app.config.update( EXT_CONFIG_VAR='some_value', ) fi = FlaskInjector([view], [configure_ext]) fi.init_app(app) app.run()
Make sure to bind extension objects as singletons.
Working Example 1: Flask-SQLAlchemy integration
This is a full working example of integrating Flask-SQLAlchemy.
We use standard SQLAlchemy models rather than the Flask-SQLAlchemy magic.
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, String Base = declarative_base() class KeyValue(Base): __tablename__ = 'data' key = Column(String, primary_key=True) value = Column(String) def __init__(self, key, value): self.key = key self.value = value
And to register the Flask-SQLAlchemy extension.
from flast.ext.sqlalchemy import SQLAlchemy class SQLAlchemyModule(Module): @inject(app=Flask) def configure(self, binder, app): db = self.configure_db(app) binder.bind(SQLAlchemy, to=db, scope=singleton) def configure_db(self, app): db = SQLAlchemy(app) Base.metadata.create_all(db.engine) db.session.add_all([ KeyValue('hello', 'world'), KeyValue('goodbye', 'cruel world'), ]) db.session.commit() return db
Working Example 2: Flask-Cache integration
class CacheModule(Module): """Configure the application.""" @inject(app=Flask) def configure(self, binder, app): binder.bind(Cache, to=Cache(app), scope=singleton)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file Flask-Injector-0.2.1.tar.gz
.
File metadata
- Download URL: Flask-Injector-0.2.1.tar.gz
- Upload date:
- Size: 6.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 43525b5984e3d01b36a6e894b096515a69204d1276817c6ce40fe556e91cbdd1 |
|
MD5 | 163ea546c44c05a007fa7a4dd5cca97f |
|
BLAKE2b-256 | 6ca09aad6623ffa596960900ad005fabd526a62b1b8a430215fcfc4e04d13aa4 |