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.

GitHub project page: https://github.com/alecthomas/flask_injector

PyPI package page: https://pypi.python.org/pypi/Flask-Injector

Features

Flask-Injector lets you inject dependencies into:

  • views

  • before_request handlers

  • after_request handlers

  • teardown_request handlers

  • template context processors

  • Jinja environment globals (functions in app.jinja_env.globals)

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.4.tar.gz (6.1 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.4-py2.py3-none-any.whl (9.1 kB view details)

Uploaded Python 2Python 3

File details

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

File metadata

File hashes

Hashes for Flask-Injector-0.3.4.tar.gz
Algorithm Hash digest
SHA256 cefb39b44192f300bc9f3aabcaaf8ac47b7d31151d92a65a865353b52d094c09
MD5 f40e390abda2de7e1521c8a7d599d1b2
BLAKE2b-256 beb30310a8ef27e88d0fcdc49d780d4db39ae3073a6b411215b89450b36e50c0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for Flask_Injector-0.3.4-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 cc283a8216638ad3b48451706fd7925990c7c57a919df8a947a6882ebf8fa031
MD5 183939ea704d46c126f039672d3d045d
BLAKE2b-256 625e35bf8c9a61fc117075da19d54bec28df55c9c70ab870442bbfa78b5482d2

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