Flask-Injector


NameFlask-Injector JSON
Version 0.15.0 PyPI version JSON
download
home_pagehttps://github.com/alecthomas/flask_injector
SummaryAdds Injector, a Dependency Injection framework, support to Flask.
upload_time2023-07-27 00:33:18
maintainer
docs_urlNone
authorAlec Thomas
requires_python
licenseBSD
keywords dependency injection flask
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Flask-Injector
==============

.. image:: https://codecov.io/gh/alecthomas/flask_injector/branch/master/graph/badge.svg
   :target: https://codecov.io/gh/alecthomas/flask_injector

.. image:: https://github.com/alecthomas/flask_injector/workflows/CI/badge.svg
   :target: https://github.com/alecthomas/flask_injector?query=workflow%3ACI+branch%3Amaster


Adds `Injector <https://github.com/alecthomas/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. You
can `find Injector on PyPI <https://pypi.org/project/injector/>`_ and `Injector
documentation on Read the Docs <https://injector.readthedocs.io/en/latest/>`_.

`Flask-Injector` is compatible with CPython 3.7+.
As of version 0.15.0 it requires Injector version 0.20.0 or greater and Flask
2.2.0 or greater.

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

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

Changelog: https://github.com/alecthomas/flask_injector/blob/master/CHANGELOG.rst

Features
--------

Flask-Injector lets you inject dependencies into:

* views (functions and class-based)
* `before_request` handlers
* `after_request` handlers
* `teardown_request` handlers
* template context processors
* error handlers
* Jinja environment globals (functions in `app.jinja_env.globals`)
* Flask-RESTFul Resource constructors
* Flask-RestPlus Resource constructors
* Flask-RESTX Resource constructors

Flask-Injector supports defining types using function annotations (Python 3),
see below.

Documentation
-------------

As Flask-Injector uses Injector under the hood you should find the
`Injector documentation <https://injector.readthedocs.io/en/latest/>`_,
including the `Injector API reference <https://injector.readthedocs.io/en/latest/api.html>`_,
helpful. The `Injector README <https://github.com/alecthomas/injector/blob/master/README.md>`_
provides a tutorial-level introduction to using Injector.

The Flask-Injector public API consists of the following:

* `FlaskInjector` class with the constructor taking the following parameters:

  * `app`, an instance of`flask.Flask` [mandatory] – the Flask application to be used
  * `modules`, an iterable of
    `Injector modules <https://injector.readthedocs.io/en/latest/api.html#injector.Binder.install>`_ [optional]
    – the Injector modules to be used.
  * `injector`, an instance of
    `injector.Injector <https://injector.readthedocs.io/en/latest/api.html#injector.Injector>`_ [optional]
    – an instance of Injector to be used if, for some reason, it's not desirable
    for `FlaskInjector` to create a new one. You're likely to not need to use this.
  * `request_scope_class`, an `injector.Scope <https://injector.readthedocs.io/en/latest/api.html#injector.Scope>`_
    subclass [optional] – the scope to be used instead of `RequestScope`. You're likely to need to use this
    except for testing.
* `RequestScope` class – an `injector.Scope <https://injector.readthedocs.io/en/latest/api.html#injector.Scope>`_
  subclass to be used for storing and reusing request-scoped dependencies
* `request` object – to be used as a class decorator or in explicit
  `bind() <https://injector.readthedocs.io/en/latest/api.html#injector.Binder.bind>`_ calls in
  Injector modules.
  
Creating an instance of `FlaskInjector` performs side-effectful configuration of the Flask
application passed to it. The following bindings are applied (if you want to modify them you
need to do it in one of the modules passed to the `FlaskInjector` constructor):

* `flask.Flask` is bound to the Flask application in the (scope: singleton)
* `flask.Config` is bound to the configuration of the Flask application
* `flask.Request` is bound to the current Flask request object, equivalent to the thread-local
  `flask.request` object (scope: request)
 
Example application using Flask-Injector
----------------------------------------

.. code:: python

    import sqlite3
    from flask import Flask, Config
    from flask.views import View
    from flask_injector import FlaskInjector
    from injector import inject

    app = Flask(__name__)

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

    @app.route("/bar")
    def bar():
        return render("bar.html")


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


    # Class-based view with injected constructor
    class Waz(View):
        @inject
        def __init__(self, db: sqlite3.Connection):
            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'))


    # In the Injector world, all dependency configuration and initialization is
    # performed in modules (https://injector.readthedocs.io/en/latest/terminology.html#module).
    # 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`:

    def configure(binder):
        binder.bind(
            sqlite3.Connection,
            to=sqlite3.Connection(':memory:'),
            scope=request,
        )
    
    # Initialize Flask-Injector. This needs to be run *after* you attached all
    # views, handlers, context processors and template globals.

    FlaskInjector(app=app, modules=[configure])

    # All that remains is to run the application

    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.

.. code:: python

    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.

.. code:: python

    from injector import Module

    class MyModule(Module):
        @provider
        @singleton
        def provide_ext(self, app: Flask) -> ExtClass:
            return ExtClass(app)

    def main():
        app = Flask(__name__)
        app.config.update(
            EXT_CONFIG_VAR='some_value',
        )

        # attach your views etc. here

        FlaskInjector(app=app, modules=[MyModule])

        app.run()

*Make sure to bind extension objects as singletons.*



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/alecthomas/flask_injector",
    "name": "Flask-Injector",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "Dependency Injection,Flask",
    "author": "Alec Thomas",
    "author_email": "alec@swapoff.org",
    "download_url": "https://files.pythonhosted.org/packages/70/f1/c9a83644c62ef7b0dec8c10d5dc18d83bd145eb442ab778279ab847e0683/Flask-Injector-0.15.0.tar.gz",
    "platform": "any",
    "description": "Flask-Injector\n==============\n\n.. image:: https://codecov.io/gh/alecthomas/flask_injector/branch/master/graph/badge.svg\n   :target: https://codecov.io/gh/alecthomas/flask_injector\n\n.. image:: https://github.com/alecthomas/flask_injector/workflows/CI/badge.svg\n   :target: https://github.com/alecthomas/flask_injector?query=workflow%3ACI+branch%3Amaster\n\n\nAdds `Injector <https://github.com/alecthomas/injector>`_ support to Flask,\nthis way there's no need to use global Flask objects, which makes testing simpler.\n\nInjector is a dependency-injection framework for Python, inspired by Guice. You\ncan `find Injector on PyPI <https://pypi.org/project/injector/>`_ and `Injector\ndocumentation on Read the Docs <https://injector.readthedocs.io/en/latest/>`_.\n\n`Flask-Injector` is compatible with CPython 3.7+.\nAs of version 0.15.0 it requires Injector version 0.20.0 or greater and Flask\n2.2.0 or greater.\n\nGitHub project page: https://github.com/alecthomas/flask_injector\n\nPyPI package page: https://pypi.org/project/Flask-Injector/\n\nChangelog: https://github.com/alecthomas/flask_injector/blob/master/CHANGELOG.rst\n\nFeatures\n--------\n\nFlask-Injector lets you inject dependencies into:\n\n* views (functions and class-based)\n* `before_request` handlers\n* `after_request` handlers\n* `teardown_request` handlers\n* template context processors\n* error handlers\n* Jinja environment globals (functions in `app.jinja_env.globals`)\n* Flask-RESTFul Resource constructors\n* Flask-RestPlus Resource constructors\n* Flask-RESTX Resource constructors\n\nFlask-Injector supports defining types using function annotations (Python 3),\nsee below.\n\nDocumentation\n-------------\n\nAs Flask-Injector uses Injector under the hood you should find the\n`Injector documentation <https://injector.readthedocs.io/en/latest/>`_,\nincluding the `Injector API reference <https://injector.readthedocs.io/en/latest/api.html>`_,\nhelpful. The `Injector README <https://github.com/alecthomas/injector/blob/master/README.md>`_\nprovides a tutorial-level introduction to using Injector.\n\nThe Flask-Injector public API consists of the following:\n\n* `FlaskInjector` class with the constructor taking the following parameters:\n\n  * `app`, an instance of`flask.Flask` [mandatory] \u2013\u00a0the Flask application to be used\n  * `modules`, an iterable of\n    `Injector modules <https://injector.readthedocs.io/en/latest/api.html#injector.Binder.install>`_ [optional]\n    \u2013 the Injector modules to be used.\n  * `injector`, an instance of\n    `injector.Injector <https://injector.readthedocs.io/en/latest/api.html#injector.Injector>`_ [optional]\n    \u2013 an instance of Injector to be used if, for some reason, it's not desirable\n    for `FlaskInjector` to create a new one. You're likely to not need to use this.\n  * `request_scope_class`, an `injector.Scope <https://injector.readthedocs.io/en/latest/api.html#injector.Scope>`_\n    subclass [optional] \u2013 the scope to be used instead of `RequestScope`. You're likely to need to use this\n    except for testing.\n* `RequestScope` class \u2013 an `injector.Scope <https://injector.readthedocs.io/en/latest/api.html#injector.Scope>`_\n  subclass to be used for storing and reusing request-scoped dependencies\n* `request` object \u2013 to be used as a class decorator or in explicit\n  `bind() <https://injector.readthedocs.io/en/latest/api.html#injector.Binder.bind>`_ calls in\n  Injector modules.\n  \nCreating an instance of `FlaskInjector` performs side-effectful configuration of the Flask\napplication passed to it. The following bindings are applied (if you want to modify them you\nneed to do it in one of the modules passed to the `FlaskInjector` constructor):\n\n* `flask.Flask` is bound to the Flask application in the (scope: singleton)\n* `flask.Config` is bound to the configuration of the Flask application\n* `flask.Request` is bound to the current Flask request object, equivalent to the thread-local\n  `flask.request` object (scope: request)\n \nExample application using Flask-Injector\n----------------------------------------\n\n.. code:: python\n\n    import sqlite3\n    from flask import Flask, Config\n    from flask.views import View\n    from flask_injector import FlaskInjector\n    from injector import inject\n\n    app = Flask(__name__)\n\n    # Configure your application by attaching views, handlers, context processors etc.:\n\n    @app.route(\"/bar\")\n    def bar():\n        return render(\"bar.html\")\n\n\n    # Route with injection\n    @app.route(\"/foo\")\n    def foo(db: sqlite3.Connection):\n        users = db.execute('SELECT * FROM users').all()\n        return render(\"foo.html\")\n\n\n    # Class-based view with injected constructor\n    class Waz(View):\n        @inject\n        def __init__(self, db: sqlite3.Connection):\n            self.db = db\n\n        def dispatch_request(self, key):\n            users = self.db.execute('SELECT * FROM users WHERE name=?', (key,)).all()\n            return 'waz'\n\n    app.add_url_rule('/waz/<key>', view_func=Waz.as_view('waz'))\n\n\n    # In the Injector world, all dependency configuration and initialization is\n    # performed in modules (https://injector.readthedocs.io/en/latest/terminology.html#module).\n    # The same is true with Flask-Injector. You can see some examples of configuring\n    # Flask extensions through modules below.\n\n    # Accordingly, the next step is to create modules for any objects we want made\n    # available to the application. Note that in this example we also use the\n    # Injector to gain access to the `flask.Config`:\n\n    def configure(binder):\n        binder.bind(\n            sqlite3.Connection,\n            to=sqlite3.Connection(':memory:'),\n            scope=request,\n        )\n    \n    # Initialize Flask-Injector. This needs to be run *after* you attached all\n    # views, handlers, context processors and template globals.\n\n    FlaskInjector(app=app, modules=[configure])\n\n    # All that remains is to run the application\n\n    app.run()\n\nSee `example.py` for a more complete example, including `Flask-SQLAlchemy` and\n`Flask-Cache` integration.\n\nSupporting Flask Extensions\n---------------------------\n\nTypically, Flask extensions are initialized at the global scope using a\npattern similar to the following.\n\n.. code:: python\n\n    app = Flask(__name__)\n    ext = ExtClass(app)\n\n    @app.route(...)\n    def view():\n        # Use ext object here...\n\nAs we don't have these globals with Flask-Injector we have to configure the\nextension the Injector way - through modules. Modules can either be subclasses\nof `injector.Module` or a callable taking an `injector.Binder` instance.\n\n.. code:: python\n\n    from injector import Module\n\n    class MyModule(Module):\n        @provider\n        @singleton\n        def provide_ext(self, app: Flask) -> ExtClass:\n            return ExtClass(app)\n\n    def main():\n        app = Flask(__name__)\n        app.config.update(\n            EXT_CONFIG_VAR='some_value',\n        )\n\n        # attach your views etc. here\n\n        FlaskInjector(app=app, modules=[MyModule])\n\n        app.run()\n\n*Make sure to bind extension objects as singletons.*\n\n\n",
    "bugtrack_url": null,
    "license": "BSD",
    "summary": "Adds Injector, a Dependency Injection framework, support to Flask.",
    "version": "0.15.0",
    "project_urls": {
        "Homepage": "https://github.com/alecthomas/flask_injector"
    },
    "split_keywords": [
        "dependency injection",
        "flask"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "44a0e7964d1d1b8fb64c62988de6a20ee06573354e0a0d9653b6e659323920e9",
                "md5": "6c49545eef2f7450efd404152b6543ac",
                "sha256": "9908904ab8d8830e5160b274fd5dd73453741c9c618d3fc6deb2b08d894f4ece"
            },
            "downloads": -1,
            "filename": "Flask_Injector-0.15.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "6c49545eef2f7450efd404152b6543ac",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": null,
            "size": 14078,
            "upload_time": "2023-07-27T00:33:16",
            "upload_time_iso_8601": "2023-07-27T00:33:16.297328Z",
            "url": "https://files.pythonhosted.org/packages/44/a0/e7964d1d1b8fb64c62988de6a20ee06573354e0a0d9653b6e659323920e9/Flask_Injector-0.15.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "70f1c9a83644c62ef7b0dec8c10d5dc18d83bd145eb442ab778279ab847e0683",
                "md5": "705ef1aa9f960a7aa8628519b1e1d507",
                "sha256": "567c69da7657b96565db990bb7c87cc0acf04e383714341954902f1ef85c5875"
            },
            "downloads": -1,
            "filename": "Flask-Injector-0.15.0.tar.gz",
            "has_sig": false,
            "md5_digest": "705ef1aa9f960a7aa8628519b1e1d507",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 13549,
            "upload_time": "2023-07-27T00:33:18",
            "upload_time_iso_8601": "2023-07-27T00:33:18.069334Z",
            "url": "https://files.pythonhosted.org/packages/70/f1/c9a83644c62ef7b0dec8c10d5dc18d83bd145eb442ab778279ab847e0683/Flask-Injector-0.15.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-27 00:33:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "alecthomas",
    "github_project": "flask_injector",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "flask-injector"
}
        
Elapsed time: 0.10514s