Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

174
Views
Use Flask's Click CLI with the app factory pattern

I define my Flask application using the app factory pattern. When using Flask-Script, I can pass the factory function to the Manager. I'd like to use Flask's built-in Click CLI instead. How do I use the factory with Click?

My current code uses Flask-Script. How do I do this with Click?

from flask import Flask
from flask_script import Manager, Shell

def create_app():
    app = Flask(__name__)
    ...
    return app

manager = Manager(create_app)

def make_shell_context():
    return dict(app=app, db=db, User=User, Role=Role)

manager.add_command('shell', Shell(make_context=make_shell_context))

if __name__ == '__main__':
    manager.run()
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

The flask command is a click interface built with flask.cli.FlaskGroup . Create your own group and pass it the factory function. Use app.shell_context_processor to add objects to the shell.

 from flask import Flask from flask.cli import FlaskGroup from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() def create_app(script_info=None): app = Flask(__name__) db.init_app(app) ... @app.shell_context_processor def shell_context(): return {'app': app, 'db': db} return app cli = FlaskGroup(create_app=create_app) @cli.command def custom_command(): pass if __name__ == '__main__': cli()

Run your file instead of the flask command. You will get the Click interface using its factory.

 FLASK_DEBUG=1 python app.py run

Ideally, create an entry point and install your package into your env. You can then call the script as a command. Create a setup.py file with at least the following.

 project/ app/ __init__.py setup.py
 from setuptools import setup, find_packages setup( name='my_app', version='1.0.0', packages=find_packages(), entry_points={ 'console_scripts': [ 'app=app:cli', ], }, )
 pip install -e /path/to/project FLASK_DEBUG=1 app run

Using your own CLI is less robust than the built-in flask command. Because your cli object is defined with your other code, a module-level error will cause the reloader to fail because it can no longer import the object. The flask command is separate from your project, so it is not affected by errors in your module.

over 4 years ago · Santiago Trujillo Report

0

To pass arguments to your app factory, you need to make use of script_info like this...

manage.py

 #!/usr/bin/env python import click import config from flask import Flask from flask.cli import FlaskGroup, pass_script_info def create_app(script_info): app = Flask(__name__) if script_info.config_mode: obj = getattr(config, script_info.config_mode) flask_config.from_object(obj) ... return app @click.group(cls=FlaskGroup, create_app=create_app) @click.option('-m', '--config-mode', default="Development") @pass_script_info def manager(script_info, config_mode): script_info.config_mode = config_mode if __name__ == "__main__": manager()

config.py

 class Config(object): TESTING = False class Production(Config): DATABASE_URI = 'mysql://user@localhost/foo' class Development(Config): DATABASE_URI = 'sqlite:///app.db' class Testing(Config): TESTING = True DATABASE_URI = 'sqlite:///:memory:'

now, on the command line, you can manage -m Production run (after adding the setup.py entry_points mentioned in @davidism, or run pip install manage.py ).

over 4 years ago · Santiago Trujillo Report

0

Newly updated for Flask >= 2.1. See my other answer for Flask < 2.1.

In order to pass arguments to our app, we store them in script_info. And in order to do that, we create a custom Click interface using flask.cli.FlaskGroup.

However, passing script_info directly to app factories is deprecated in Flask 2, so we use Click's get_current_context function to get the current context and then access script_info from that context.

manage.py

#!/usr/bin/env python

import click
import config

from click import get_current_context
from flask import Flask
from flask.cli import FlaskGroup, pass_script_info


def create_app(*args, **kwargs):
    app = Flask(__name__)
    ctx = get_current_context(silent=True)

    if ctx:
        script_info = ctx.obj
        config_mode = script_info.config_mode
    elif kwargs.get("config_mode"):
        # Production server, e.g., gunincorn 
        # We don't have access to the current context, so must
        # read kwargs instead.
        config_mode = kwargs["config_mode"]

    ...    
    return app


@click.group(cls=FlaskGroup, create_app=create_app)
@click.option('-m', '--config-mode', default="Development")
@pass_script_info
def manager(script_info, config_mode):
    script_info.config_mode = config_mode
    ...


if __name__ == "__main__":
    manager()

Now you can run the dev server and set your desired config_mode by using either -m or --config-mode. Note, until Flask 2.1 drops you have to install Flask@aa13521d42bfdb

pip install git+https://github.com/pallets/flask.git@aa13521d42bfdb
python manage.py -m Production run

Production servers like gunincorn don't have access to the current context, so we pass what we need via kwargs.

gunicorn app:create_app\(config_mode=\'Production\'\) -w 3 -k gevent
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!