Search code examples
python-click

Python click to restart a command with all parameters cleared


My script below is saved in 'bike.py' and registered as bike shell command. I'd like to run a simple bike filter -c chicago -m 1 -d 1 command to explore data for chicago as city, 1 as month and 1 as day of week. I use prompt=True to catch any options unspecified in the command.

I'd also like to be able to restart the command at the end and have all the existing parameters cleared, so that the command will prompt me for city, month and day of week at restart. However, the code can't do that. It just runs what's inside the script and gives me error because the script can't run without the arguments passed in.

How should I do this with click?

@click.group()
@click.pass_context
def main():
    ctx.ensure_object(dict)


@main.command()
@click.option('-city', '-c', prompt=True)
@click.option('-month', '-m', prompt=True)
@click.option('-day_of_week', '-d', prompt=True)
@click.pass_context
def filter(ctx, city, month, day_of_week):
    # load filtered data
    ...

    # restart the program
    if click.confirm('Restart to explore another dataset?') if not False:
        import sys
        sys.argv.clear()
        ctx.invoke(filter)

Solution

  • You could change your filter command so you do the prompting manually. I don't think Click will know to prompt otherwise, since this is not a common use-case and doesn't conform to the no-magic click style guide.

    @main.command()
    @click.option('-city', '-c')
    @click.option('-month', '-m')
    @click.option('-day_of_week', '-d')
    @click.pass_context
    def filter(ctx, city, month, day_of_week):
        # prompt if not passed in
        if city is None:
            city = click.prompt('City: ')
        if month is None:
            month = click.prompt('Month: ')
        if day_of_week is None:
            day_of_week = click.prompt('Day of the week: ')
    
        # load filtered data
        ...
    
        # restart the program
        if click.confirm('Restart to explore another dataset?'):
            ctx.invoke(filter)
    

    Alternatively, if you really want to rely on the built-in functionality, you might be able to get some mileage by overriding the Option class and prompt functionality.