Flask-extension management

When your Python Flask application reaches a certain size, or starts to use a number of different Flask extensions, you're bound to start running into issues with how the application is initialized.

To review, the factory pattern states that you should use a function to create your flask application object, like so:

def create_app():
  app = Flask(__name__)
  # do stuff
  return app


But adding in extensions can get problematic:

def create_app():
  app = Flask(__name__)
  db = SQLAlchemy()

  mail = Mail()
  return app


Coming from a small Flask app that set up the app directly, at first I thought: this is great! I can re-create my app object for each set of tests. I can test initializing it in different ways if I need to. But as soon as I added in the extensions all my tests started failing.

It turns out that naively adding in extensions this way is bad. We don't want application specific state to be kept in extension object; we want the extension object to be usable by multiple apps. And most Flask extensions are actually designed to work this way.

What you do is break out your extensions into their own module. Each extension will typically provide an init_app method that can be initialized with the application object being created. So the factory now looks like this:

from extensions import db, mail

def create_app():
  app = Flask(__name__)
  db.init_app(app)
  mail.init_app(app)
  return app

And in extensions.py:

from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail

db = SQLAlchemy()
mail = Mail()


 I have run across at least one Flask extension that doesn't support this (the author considers the extension to be a Singleton), so it's not 100% universal. But it will save a lot of headaches.

Comments

Popular posts from this blog

Monitoring with statsd and CloudWatch

Xen, "hwcap 0 nosegneg", and -mno-tls-direct-seg-refs

A Grand Adventure: compiling transmission on my home router