jwg
jwg

Reputation: 5837

How should I create a Flask extension which depends on another extension?

I want to create a Flask extension which depends on another Flask extension. For the sake of argument, say that it's Flask-Foo, and that it needs Flask-Redis to store some specific data in a Redis database.

I know that I can add an install dependency to Flask-Redis. However I don't understand how I should instantiate and initialize Flask-Redis.

  1. The setup for Flask-Foo sets up the Flask-Redis object. The drawback of this is that it assumes that the app isn't also using Flask-Redis for some other reason, configured explicitly outside of Flask-Foo. If it is, we get two objects which exist side-by-side, which seems wrong.

  2. The user has to themselves instantiate and configure Flask-Redis. Flask-Foo checks that it has been initialized for that app, and complains otherwise. The problem with this is that it seems to impose boilerplate on the user - why should they have to set up Flask-Redis to use Flask-Foo, when they have no other knowledge or interest in the configuration of Flask-Redis? Furthermore, aren't we asking for trouble if this means that Flask-Foo.init_app() always has to be called after Flask-Redis.init_app()?

  3. Don't use Flask-Redis. Use the Redis package directly, and manage the connection in Flask-Foo code. This would probably avoid the above problems. But it seems unelegant - we will basically have to resolve problems solved by Flask-Redis. If Flask-Foo goes on to support an alternative database, it will become complicated as we have to maintain code to manage the different types of connection.

Just to be clear, this is not a question specifically about Flask-Redis or how it works! I just want to understand what is generally the right way to build an extension on top of an extension.

Upvotes: 4

Views: 978

Answers (2)

Legolas Bloom
Legolas Bloom

Reputation: 1805

You can pass depend extension to init_app. http://flask.pocoo.org/docs/1.0/extensiondev/

flask_foo/init.py

class FooManager:

    def __init__(self, app=None, db=None, **kwargs):
        self.app = app
        if app is not None:
            self.init_app(app, db, **kwargs)

    def init_app(self, app, db, **kwargs):
        self.db = db

        app.config.setdefault('xxx', xxx)

        # Bind Flask-Foo to app
        app.foo_manager = self

Now, you can get foo_manager object from current_app like this:

models.py

from flask import current_app

db = current_app.foo_manager.db


class XXX(db.Model):
    pass

Last, maybe you must register foo by app_context():

run.py

with app.app_context():
    FooManager(app, db)  # or xx = FooManager(); xx.init_app(app, db)

wonderful, depend extension works good for us.

Other tip: https://stackoverflow.com/a/51739367/5204664

Upvotes: 1

Sergei Popinevskii
Sergei Popinevskii

Reputation: 126

Flask extension has the same structure as a python module. You should specify all requirements in setup.py file. For example flask-babel

install_requires=[
    'Flask',
    'Babel>=2.3',
    'Jinja2>=2.5'
],

Upvotes: 0

Related Questions