Skip to main content

Adds Injector, a Dependency Injection framework, support to Flask.

Project description

Build status

Adds Injector support to Flask, this way there’s no need to use global Flask objects, which makes testing simpler.

Injector is a dependency-injection framework for Python, inspired by Guice.

Flask-Injector is compatible with CPython 2.6-2.7, 3.3+ and PyPy 1.9+. As of version 0.3.0 it requires Injector version 0.7.4 or greater.

Example application using flask_injector

Create your Flask application:

import sqlite3
from flask import Flask, Config
from flask.views import View
from flask_injector import init_app, post_init_app
from injector import Injector, inject

app = Flask(__name__)

Update the Flask app configuration as normal, additionally passing in any configuration for modules:

app.config.update(
    DB_CONNECTION_STRING=':memory:',
)

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:

# 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,
    )

Now perform Injector Flask application integration initialization. This needs to be run before any views, handlers, etc. are configured for the application:

injector = init_app(app=app, modules=[configure])

You can also provide already existing Injector instance:

injector = your_initialization_code()
# ...
init_app(app=app, injector=injector)

Configure your application by attaching views, handlers, context processors etc.:

# Putting all views configuration in a function is an example of how can
# you stop depending on global app object
def configure_views(app):
    @app.route("/bar")
    def bar():
        return render("bar.html")


    # Route with injection
    @app.route("/foo")
    @inject(db=sqlite3.Connection)
    def foo(db):
        users = db.execute('SELECT * FROM users').all()
        return render("foo.html")


    # Class-based view with injected constructor
    class Waz(View):
        @inject(db=sqlite3.Connection)
        def __init__(self, db):
            self.db = db

        def dispatch_request(self, key):
            users = self.db.execute('SELECT * FROM users WHERE name=?', (key,)).all()
            return 'waz'

    app.add_url_rule('/waz/<key>', view_func=Waz.as_view('waz'))

configure_views(app)

Run the post-initialization step. This needs to be run only after you attached all views, handlers etc.:

post_init_app(app=app, injector=injector)

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',
    )

    injector = init_app(app=app, modules=[configure_ext])
    # attach your views etc. here
    post_init_app(app=app, injector=injector)

    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

@inject(app=Flask)
class FlaskSQLAlchemyModule(Module):
    def configure(self, binder):
        db = self.configure_db(self.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

@inject(app=Flask)
class CacheModule(Module):
    """Configure the application."""
    def configure(self, binder):
        binder.bind(Cache, to=Cache(self.app), scope=singleton)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

Flask-Injector-0.3.3.tar.gz (5.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

Flask_Injector-0.3.3-py2.py3-none-any.whl (8.8 kB view details)

Uploaded Python 2Python 3

File details

Details for the file Flask-Injector-0.3.3.tar.gz.

File metadata

File hashes

Hashes for Flask-Injector-0.3.3.tar.gz
Algorithm Hash digest
SHA256 791d6600ceaf96607afda1feae864e21911da064fdde54f4646345a70f7b41b4
MD5 6d4a0036c7e58916f752bc0013d634e0
BLAKE2b-256 5106b000baacc0b0fff55f3fd4f1e6d3a5f69171761a5b5ee7e58d3ba41ca75a

See more details on using hashes here.

File details

Details for the file Flask_Injector-0.3.3-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for Flask_Injector-0.3.3-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 6f27131229bf4c7896a469fd62c1404d6d62e9b9e62bcc7caaf910c99a6ae008
MD5 146363f0142b907ba1d9bd299de4cc3e
BLAKE2b-256 903d80ae660d201f1d1ee463a69c789b0ae7c788a7a1e979eba7df9fcf2d296a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page