0

I have this python click CLI design (wificli.py). At the end of command execution, it prints only respective print messages.

For example, when executed command python3.7 wificli.py png, it prints only png and when executed command python3.7 wificli.py terminal it prints only terminal.

As I have shown, I am expecting that it would also print End of start function and End of the main function but it is not. The idea is that to do clean up of resources only at one place rather than at each exit point of the respective command.

import click

@click.group()
@click.option('--ssid', help='WiFi network name.')
@click.option('--security', type=click.Choice(['WEP', 'WPA', '']))
@click.option('--password', help='WiFi password.')
@click.pass_context
def main(ctx, ssid: str, security: str = '', password: str = ''):
    ctx.obj['ssid'] = ssid
    ctx.obj['security'] = security
    ctx.obj['password'] = password


@main.command()
@click.pass_context
def terminal(ctx):
    print('terminal')

@main.command()
@click.option('--filename', help='full path to the png file')
@click.pass_context
def png(ctx, filename, scale: int = 10):
    print('png')

def start():
    main(obj={})
    print('End of start function')

if __name__ == '__main__':
    start()
    print('End of main function')

When executed

3 Answers 3

1

As you've not asked a specific question, I can only post what worked for me with the reasoning behind it, and if this is not what you are looking for, I apologize in advance.

@main.resultcallback()
def process_result(result, **kwargs):
    print('End of start function')
    click.get_current_context().obj['callback']()

def start():
    main(obj={'callback': lambda: print('End of main function')})

So, the resultcallback seems to be the suggested way of handling the termination of the group, and the invoked command. In our case, it prints End of start function, because at that point, the start function has finished executing, so we are wrapping up before terminating main. Then, it retrieves the callback passed in via the context, and executes that.

I am not sure if this is the idiomatic way of doing it, but it seems to have the intended behaviour.

For the result callback, a similar question was answered here

As to what exactly is causing this behaviour, and this is only a guess based on some quick experimentation with placing yield in the group or the command, I suspect some kind of thread/processor is spawned to handle the execution of the group and its command.

Hope this helps!

Sign up to request clarification or add additional context in comments.

Comments

1

click's main() always raises a SystemExit. Quoting the documentation:

This will always terminate the application after a call. If this is not wanted, SystemExit needs to be caught.

In your example, change start() to:

def start():
    try:
        main(obj={})
    except SystemExit as err:
        # re-raise unless main() finished without an error
        if err.code:
            raise
    print('End of start function')

Comments

0

See the click docs here also this answer here

# Main Runtime call at bottom of your code
start(standalone_mode=False)

# or e.g
main(standalone_mode=False)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.