Flask: Default flask.cli commands are not override-able

Created on 10 Sep 2016  路  5Comments  路  Source: pallets/flask

The default commands run and shell cannot be overridden.

Using a custom command called shell, I expect the custom shell to override the builtin shell

@app.cli.command('shell', short_help='My custom shell')
def shell():
    pass

But running --help still produces flask.cli.shell's help

> python -m flask
Usage: python -m flask [OPTIONS] COMMAND [ARGS]...

  This shell command acts as general utility script for Flask applications.

  It loads the application configured (either through the FLASK_APP
  environment variable) and then provides commands either provided by the
  application or Flask itself.

  The most useful commands are the "run" and "shell" command.

  Example usage:

    $ export FLASK_APP=hello
    $ export FLASK_DEBUG=1
    $ flask run

Options:
  --help  Show this message and exit.

Commands:
  run    Runs a development server.
  shell  Runs a shell in the app context.

And running gives me flask.cli.shell's shell

> python -m flask shell

Python 3.5.2 (default, Jul 17 2016, 00:00:00) 
[GCC 4.8.4] on linux
App: wallet
Instance: app/instance
>>> 

Also,

@app.cli.command('shell_plus', short_help='bar')
def shell_plus_1():
    pass

@app.cli.command('shell_plus', short_help='foo')
def shell_plus_2():
    pass

has the behaviour I expect

Usage: python -m flask [OPTIONS] COMMAND [ARGS]...

  This shell command acts as general utility script for Flask applications.

  It loads the application configured (either through the FLASK_APP
  environment variable) and then provides commands either provided by the
  application or Flask itself.

  The most useful commands are the "run" and "shell" command.

  Example usage:

    $ export FLASK_APP=hello
    $ export FLASK_DEBUG=1
    $ flask run

Options:
  --help  Show this message and exit.

Commands:
  run         Runs a development server.
  shell       Runs a shell in the app context.
  shell_plus  foo

Most helpful comment

from flask.cli import FlaskGroup, run_command

cli = FlaskGroup(add_default_commands=False, create_app=create_app)
cli.add_command(run_command)

@cli.command('shell', short_help='Starts an interactive shell in an app context.')
def shell_command():
    ctx = current_app.make_shell_context()

    try:
        from IPython import start_ipython
        start_ipython(argv=(), user_ns=ctx)
    except ImportError:
        from code import interact
        interact(local=ctx)

Create your own FlaskGroup, omit the default commands, add the run command, add your own shell command.

@mrecachinas PRs are always welcome, for discussion even if we don't end up merging it. I'd be interested to see what you changed.

All 5 comments

This appears to be the intended behavior to ensure basic script functionality in the event the application fails. See https://github.com/pallets/flask/blob/master/flask/cli.py#L329-L349.

If there is internal interest in changing that, I have a patch ready for review.

from flask.cli import FlaskGroup, run_command

cli = FlaskGroup(add_default_commands=False, create_app=create_app)
cli.add_command(run_command)

@cli.command('shell', short_help='Starts an interactive shell in an app context.')
def shell_command():
    ctx = current_app.make_shell_context()

    try:
        from IPython import start_ipython
        start_ipython(argv=(), user_ns=ctx)
    except ImportError:
        from code import interact
        interact(local=ctx)

Create your own FlaskGroup, omit the default commands, add the run command, add your own shell command.

@mrecachinas PRs are always welcome, for discussion even if we don't end up merging it. I'd be interested to see what you changed.

How to use flask.cli to launch the program in factory environment?

I know how to use flask_script and I have found a solution by using 'click' to make my program running. But the official document propose to use flask.cli instead of flask_script extension while I think 'click' solution is a dirty solution.

As davidism propose the code:

from flask.cli import FlaskGroup, run_command

cli = FlaskGroup(add_default_commands=False, create_app=create_app)
cli.add_command(run_command)

@cli.command('shell', short_help='Starts an interactive shell in an app context.')
def shell_command():
    ctx = current_app.make_shell_context()

    try:
        from IPython import start_ipython
        start_ipython(argv=(), user_ns=ctx)
    except ImportError:
        from code import interact
        interact(local=ctx)

It seems that there is a clean method to use 'flask.cli' by instantiating the 'FlaskGroup'. But then? What code should I write in 'if __name__ == "__main__":' segment? I don't know how to run this cli, by decorator like 'click' does or something else?

There is absolutely no reason to override the shell command like you did - if you want ipython, simply pip install flask-shell-ipython, then the flask shell command will use ipython instead of the default python REPL.

while I think 'click' solution is a dirty solution

Would you care to elaborate? Possibly on IRC since this seem off-topic for the issue tracker.

As Thief said, use the extension now. But in case you still want to do it manually, it's just like all other Click applications: you call cli.main().

Was this page helpful?
0 / 5 - 0 ratings