flask-db icon indicating copy to clipboard operation
flask-db copied to clipboard

[Feature request] Make --help from "flask db migrate" return original help text.

Open dwreeves opened this issue 4 years ago • 4 comments

At the moment, the "--help" is not very helpful.

Actual behavior

(venv) user@pc project % flask db migrate revision --help
Usage: flask db migrate [OPTIONS] [ALEMBIC_ARGS]...

  Wrap the alembic CLI tool (defaults to running upgrade head).

Options:
  --help  Show this message and exit.

Proposed behavior

Alternative behavior for Flask-DB would be to return the actual help documentation from alembic:

(venv) user@pc project % flask db migrate revision --help
usage: alembic revision [-h] [-m MESSAGE] [--autogenerate] [--sql] [--head HEAD] [--splice]
                        [--branch-label BRANCH_LABEL] [--version-path VERSION_PATH] [--rev-id REV_ID]
                        [--depends-on DEPENDS_ON]

optional arguments:
  -h, --help            show this help message and exit
  -m MESSAGE, --message MESSAGE
                        Message string to use with 'revision'
  --autogenerate        Populate revision script with candidate migration operations, based on
                        comparison of database to model.
  --sql                 Don't emit SQL to database - dump to standard output/file instead. See docs on
                        offline mode.
  --head HEAD           Specify head revision or <branchname>@head to base new revision on.
  --splice              Allow a non-head revision as the 'head' to splice onto
  --branch-label BRANCH_LABEL
                        Specify a branch label to apply to the new revision
  --version-path VERSION_PATH
                        Specify specific path from config for version file
  --rev-id REV_ID       Specify a hardcoded revision id instead of generating one
  --depends-on DEPENDS_ON
                        Specify one or more revision identifiers which this revision should depend on.

Implementing this

To implement, add help_option_names=[] to the context_settings of the migrate command. At the moment, the Click context sees the --help before the Alembic CLI does.

# Old

@db.command(context_settings=dict(ignore_unknown_options=True))
@click.argument("alembic_args", nargs=-1, type=click.UNPROCESSED)
@with_appcontext
def migrate(alembic_args):
    ...

# New

@db.command(context_settings=dict(ignore_unknown_options=True,
                                  help_option_names=[]))
@click.argument("alembic_args", nargs=-1, type=click.UNPROCESSED)
@with_appcontext
def migrate(alembic_args):
    ...

Alternatively, you can implement the --help so that when you run exactly flask db migrate --help it returns the Click docs, but provides the alembic docs when you invoke an Alembic subcommand. Something like this? I would need to play with it more to get super sane default behavior.

@db.command(context_settings=dict(ignore_unknown_options=True,
                                  help_option_names=[]))
@click.argument("alembic_args", nargs=-1, type=click.UNPROCESSED)
@with_appcontext
@click.pass_context
def migrate(ctx, alembic_args):
    if len(ctx.args) == 1 and ctx.args[0] == '--help':
        return ctx.get_help_option_names(migrate)
    ...

Small problem with this approach, which is that the help text will say usage: alembic revision ... instead of usage: flask db migrate revision .... Fixing that would take more work. But even with the simple implementation, I have such a strong instinct to rely on --help for options, I think having it work the way you'd mostly expect beats the downside of not returning anything.


What do you think?

dwreeves avatar Jun 16 '21 00:06 dwreeves

Hi,

This is mentioned in the readme at https://github.com/nickjj/flask-db#migrate btw,, a workaround is to run -h instead of --help to get Alembic's help. I know it's kind of lame but like you've discovered it's not straight forward to figure out how to list out 2 different help menus with the same flag.

It's a tough call. Since db migrate is an alias to alembic I think I'm ok with db migrate --help showing Alembic's help menu because the db migrate command from this extension's point of view has no arguments or flags since it's an alias to alembic and I would guess the natural behavior there is to always want Alembic's help menu.

nickjj avatar Jun 16 '21 09:06 nickjj

Totally missed that in the readme.

The existing default behavior is defensible for the case of flask db migrate --help specifically, it feels a little overkill that it follows through to subcommands like flask db migrate revision --help. So using something like if len(ctx.args) == 1 and ctx.args[0] == '--help' lets one distinguish those two cases.

dwreeves avatar Jun 16 '21 14:06 dwreeves

Are you saying if you ran flask db migrate --help you would expect to see Click's help menu for Flask-DB instead of Alembic's list of available commands, even if flask db migrate itself technically has no flags or arguments?

nickjj avatar Jun 16 '21 14:06 nickjj

I should have been clearer!

flask db migrate --help

Normally I would expect a list of all the subcommands plus a description of the default behavior, like a typical CLI. Doing that is tough though because:

  • alembic --help doesn't describe the default behavior of flask db migrate, which is to run alembic ugprade head.
  • The default help text doesn't list the subcommands available because of how Flask-DB is inherently designed to arbitrarily wrap Alembic.

So without expending lots of effort, you get to choose between describing default behavior or returning alembic --help.

Current behavior is the former, which is defensible. As you said, "you've discovered it's not straight forward to figure out how to list out 2 different help menus with the same flag," so you picked one.

flask db migrate [subcommand] --help

^ This is where I am a bit more confident that --help should return the Alembic documentation, because the default behavior of flask db migrate to run alembic upgrade head no longer applies; it's a pure wrapper around Alembic once you specify a subcommand. So in this case I think the only reasonable default behavior is to return Alembic's docs because "2 different help menus" doesn't apply anymore, just the one.

So in my personal opinion I think the best behavior here is have the context run ctx.get_help_option_names(migrate) when no subcommands are specified, otherwise pass to Alembic; the final snippet of code I listed should achieve that goal. (warning: didn't test, just winged it based on my understanding of Click.)

dwreeves avatar Jun 16 '21 20:06 dwreeves